﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using SoftwareConsulting.BI11.Studio.BasicEntities;
using SoftwareConsulting.BI11.Studio.Core.Project;
using SoftwareConsulting.BI11.Studio.Core.Project.Metadata;
using SoftwareConsulting.BI11.Studio.Core.Project.SituationsHierarchy;
using SoftwareConsulting.BI11.Studio.Core.Project.SituationsHierarchy.RulesContainers;
using SoftwareConsulting.BI11.Studio.InternalServices;
using SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.SituationsHierarchy.RulesContainers;
using SoftwareConsulting.Interfaces.BasicEntities;
using SoftwareConsulting.BI11.Studio.UI.Properties;
using SoftwareConsulting.BI11.NumericalMethods.Geometry;

namespace SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.SituationsHierarchy
{
    public enum CharacteristicsDataGridColumn { IndicatorLimiter, Mandatory, Name, Indicator, Value };//колонки датагрида характеристик

    public partial class SituationsHierarchyForm : UniqueForm
    {
        bool ReallyClose = false; //окончательное закрытие формы
        private SituationsArea _CurrentSituationsArea; //текущее рабочее пространство иерархии ситуаций
        private int _selectedRuleIndex; //выделенное правило контейнера правил
        private List<Point> _rulesBorders; //границы правил в списке правил        
        private Guid _editingCharacteristicWithRulesContainerId; //идентификатор редактируемой характеристики в режиме редактора контейнера правил
        private Guid _editingRulesContainerId; //идентификатор редактируемого контейнера правил в режиме редактора контейнера правил
        private bool _inRulesContainerEditor = false; //флаг режима редактора контейнера правил
        private bool programdatagriddirty = true; //флаг программного изменения датагрида характеристик        
        private bool _programRulesContainerDirty = false; //флаг программного изменения направления МЛВ в контейнерах правил
        private bool _mapscrolling = false; //флаг скроллирования по карте        
        private bool _mousebuttonPressing = false; //флаг зажатой кнопки мыши
        private int _currentSituationsAreaRefreshInterval; //интервал между перерисовками РП
        private int _currentMapRefreshInterval; //интервал между перерисовками карты
        private float _scaleFactorX; //коэффициент масштабирования карты относительно РП по X
        private float _scaleFactorY; //коэффициент масштабирования карты относительно РП по Y                
        private SmoothingMode _smoothMode = SmoothingMode.HighQuality; //качество прорисовки РП        
        private bool _blockScrollInfoReading=false; //флаг блокировки запоминания информации о скролле        
        private DateTime _mapLastRefreshTime = DateTime.Now; //время последнего обновления карты
        private Timer _mapSuspendedRefreshTimer; //таймер отложенного обновления карты
        private bool _mapSuspendedRefresh = false; //флаг отложенного обновления карты
        private DateTime _DSLastRefreshTime = DateTime.Now; //время последнего обновления РП
        private Timer _SASuspendedRefreshTimer; //таймер отложенного обновления РП
        private bool _SASuspendedRefresh = false; //флаг отложенного обновления РП
        private int _scrollX; //положение скролла по X
        private int _scrollY; //положение скролла по Y
        private int _mapWindowW; //ширина окна просмотра карты
        private int _mapWindowH; //высота окна просмотра карты
        private string _lastcharacteristicname = ""; //строка для временного хранения предыдущего имени характеристики        
        private Graphics _drawingPanelGraphics=null; //graphics для рисования на РП/карте
        private Point _curmouseposition; //текущее положение курсора мышки на РП                

        public SituationsArea CurrentSituationsArea
        {
            get
            {
                return _CurrentSituationsArea;
            }
            set
            {
                _CurrentSituationsArea = value;
            }
        }

        /// <summary>
        /// Геттер-сеттер идентификатора редактируемого контейнера правил в режиме редактора контейнеров правил
        /// </summary>
        public Guid EditingRulesContainerId
        {
            get
            {
                return _editingRulesContainerId;
            }
            set
            {
                _editingRulesContainerId = value;
            }
        }

        /// <summary>
        /// Геттер флага режима редактора контейнера правил
        /// </summary>
        public bool InRulesContainerEditor
        {
            get
            {
                return _inRulesContainerEditor;
            }
        }

        /// <summary>
        /// Отображает редактор контейнера правил, если надо
        /// </summary>
        public void RestoreRulesContainerEditorIfNecessary()
        {
            if (_editingRulesContainerId != Guid.Empty)
            {
                ShowOrHideRulesContainerEditor(ProjectLink.GetCharacteristicById(_editingCharacteristicWithRulesContainerId), true);
            }            
        }
        /// <summary>
        /// Геттер-сеттер флага блокировки запоминания информации о скролле
        /// </summary>
        public bool BlockScrollInfoReading
        {
            get
            {
                return _blockScrollInfoReading;
            }
            set
            {
                _blockScrollInfoReading = value;
            }
        }

        /// <summary>
        /// Читает информацию о скролле
        /// </summary>
        public void ReadScrollInfo()
        {
            if (!_blockScrollInfoReading)
            {
                SplitterPanel sp = splitContainer1.Panel2;
                _scrollX = sp.HorizontalScroll.Value;
                _scrollY = sp.VerticalScroll.Value;
            }
        }

        /// <summary>
        /// Применяет запомненную информацию о скролле
        /// </summary>
        public void SetScrollInfo()
        {
            SplitterPanel sp = splitContainer1.Panel2;
            HScrollProperties hs = sp.HorizontalScroll;
            VScrollProperties vs = sp.VerticalScroll;
            _scrollX = _scrollX <= hs.Maximum ? _scrollX : hs.Maximum;
            _scrollY = _scrollY <= vs.Maximum ? _scrollY : vs.Maximum;
            sp.AutoScrollPosition = new Point(_scrollX, _scrollY);
            RefreshMap();
        }

        /// <summary>
        /// Включает/выключает возможность изменения описания события
        /// </summary>
        /// <param name="toen"></param>
        public void RefreshSelectedSituationActionsAbilities()
        {
            SituationBox sitbox = CurrentSituationsArea.SelectedSituationBox;
            InherKindToolStripButton.Enabled = (sitbox != null) && (ProjectLink.GetItemById(sitbox.SituationId).IsA != null);
            PhrasesToolStripButton.Enabled = sitbox != null;
            IHierarchy<SituationBox> sitboxes = CurrentSituationsArea.MultiselectedSituationBoxes;
            CenterSituationToolStripButton.Enabled = sitboxes == null || sitboxes.ItemsCount > 0;
        }
        
        public ErrorProvider SituationIncorrectProvider
        {
            get
            {
                return SituationIncorrentNameErrorProvider;
            }            
        }
        
        /// <summary>
        /// Возвращает связь с проектом
        /// </summary>
        public ProjectDescriptor ProjectLink
        {
            get
            {
                return _CurrentSituationsArea.ProjectLink;
            }            
        }

        /// <summary>
        /// Инициализация компонентов формы
        /// </summary>
        public SituationsHierarchyForm(ProjectExplorerForm projectExplorerLink)
            : base()
        {
            CurrentSituationsArea = new SituationsArea(projectExplorerLink, this);
            _currentSituationsAreaRefreshInterval = SituationsArea.SituationsAreaRefreshInterval;
            _currentMapRefreshInterval = SituationsArea.MapRefreshInterval;
            _mapSuspendedRefreshTimer = new Timer();
            _mapSuspendedRefreshTimer.Enabled = true;
            _mapSuspendedRefreshTimer.Interval = _currentMapRefreshInterval;
            _mapSuspendedRefreshTimer.Tick += new EventHandler(_mapRefreshSuspended_Tick);
            _SASuspendedRefreshTimer = new Timer();
            _SASuspendedRefreshTimer.Enabled = true;
            _SASuspendedRefreshTimer.Interval = _currentSituationsAreaRefreshInterval;
            _SASuspendedRefreshTimer.Tick += new EventHandler(_DSSuspendedRefreshTimer_Tick);
            InitializeComponent();
        }

        /// <summary>
        /// Обработка тика таймер отложенного обновления РП
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _DSSuspendedRefreshTimer_Tick(object sender, EventArgs e)
        {            
            RefreshSituationsAreaImmediately();         
        }

        /// <summary>
        /// Обработка тика таймера отложенного обновления карты
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _mapRefreshSuspended_Tick(object sender, EventArgs e)
        {                        
            RefreshMapImmediately();            
        }

        /// <summary>
        /// Закрытие окна
        /// </summary>
        public void CloseAbsolutely()
        {
            ReallyClose = true;
            Close();
        }

        /// <summary>
        /// Смена режима
        /// </summary>
        public void SetMode(SituationsHierarchyState state)
        {
            CurrentSituationsArea.State = state;
            createSituationToolStripButton.Checked = state == SituationsHierarchyState.NewSituation;
            PointerToolStripButton.Checked = state == SituationsHierarchyState.Pointer;
            UpdateMouseCursor();
            bool notlink = state == SituationsHierarchyState.NewSituation || state == SituationsHierarchyState.Pointer;
            SituationsAreaTip = notlink ? "" : Resources.BI_SITUATIONSHIERARCHY_TOOLTIP_SELECT_START;
            if (notlink)
            {
                SituationBox sitbox = CurrentSituationsArea.GetStartLinkPoint();
                if (sitbox != null)
                {
                    sitbox.IsLinkStart = false;
                }
            }
            CurrentSituationsArea.IsMultiselectByCtrl = false;
        }
 
        /// <summary>
        /// Обновление вида курсора мышки
        /// </summary>
        private void UpdateMouseCursor()
        {
            Cursor cursor = Cursors.Default;
            switch (CurrentSituationsArea.State)
            {
                case SituationsHierarchyState.NewSituation:
                    cursor = Cursors.Hand;
                    break;
                case SituationsHierarchyState.IsA:
                case SituationsHierarchyState.Subsituation:
                case SituationsHierarchyState.NextStep:
                case SituationsHierarchyState.StepOnFail:
                    cursor = Cursors.Cross;
                    break;                
            }
            SituationsAreaPanel.Cursor = cursor;
        }

        /// <summary>
        /// Заполнение комбика со значениями характеристики
        /// </summary>
        /// <param name="combo"></param>
        public void FillCharacteristicValueComboBox(DataGridViewComboBoxCell combo, Characteristic characteristic)
        {
            combo.Items.Clear();
            IIndicator chind = characteristic.UsedIndicator;
            if (!Assert.FailIf(chind == null, Assert.Id.Assert00146))
                return;            
            int c = chind.GetIndicatorValuesCount();
            for (int i = 0; i < c; i++)
            {
                IndicatorValue iv = chind.GetIndicatorValueByPosition(i);
                object obj = iv.Value;
                if ((characteristic.IndicatorLimiter != null) && (!characteristic.IndicatorLimiter.HasItem(obj)))
                    continue;
                if (!Indicator.IsSituationType(chind.Type))
                {
                    if (obj != null)
                    {
                        combo.Items.Add(obj.ToString());
                    }
                    else
                    {
                        combo.Items.Add(Constants.NullDoesNotMatterString);
                    }
                    continue;
                }                
                Situation sit = obj as Situation;
                if (sit != null)
                {
                    combo.Items.Add("<" + sit.ToString() + ">");
                }
                else
                {
                    combo.Items.Add(Constants.NullDoesNotMatterString);
                }                                
            }              
        }

        /// <summary>
        /// Выбирает указанное значение в комбобоксе со значениями характеристики
        /// </summary>        
        public static void SelectCharacteristicValueInComboBox(DataGridViewComboBoxCell combo, object value)
        {
            int c = combo.Items.Count;
            for (int i = 0; i < c; i++)
            {
                object item = combo.Items[i];
                string itemstring = item as string;
                Situation sit = value as Situation;
                if ((sit == null) && ((item.Equals(value) || ((value is bool) || (value is int) || (value is float)) && (itemstring == value.ToString()))) || (value == null) && (itemstring != null) && (GeneralMethods.IsNullString(item)))
                {                    
                    combo.Value = item;
                }   
                else
                {
                    if ((sit != null) && (itemstring == "<" + sit.Name + ">"))
                    {
                        combo.Value = "<" + sit.Name + ">";
                    }
                }
            }
        }

        /// <summary>
        /// Обновляет состояние кнопок на тулбаре датагрида характеристик
        /// </summary>
        private void UpdateCharacteristicsGridToolBar()
        {
            int c = CharacteristicsDataGrid.SelectedRows.Count;
            bool IsSelected = (c > 0);
            CharacteristicsDataGridToolStrip.Visible = CharacteristicsDataGrid.Visible;
            AddCharacteristicToolStripDropDownButton.Enabled = CharacteristicsDataGrid.Visible;
            DeleteCharacteristicToolStripButton.Enabled = IsSelected;            
            УдалитьХарактеристикуToolStripMenuItem.Enabled = IsSelected;
            RenameCharacteristicToolStripButton.Enabled = IsSelected&&(c==1);
            ПереименоватьХарактеристикуToolStripMenuItem.Enabled = IsSelected && (c == 1);
            DataGridViewRow dr = c == 0 ? null : CharacteristicsDataGrid.SelectedRows[0];            
            bool IsNotUp = IsSelected && (dr != null) && (dr.Index > 0);
            bool IsNotDown = IsSelected && (dr != null) && (dr.Index < (CharacteristicsDataGrid.Rows.Count - 1));
            UpCharacteristicToolStripButton.Enabled = IsNotUp;
            DownCharacteristicToolStripButton.Enabled = IsNotDown;
            поднятьToolStripMenuItem.Enabled = IsNotUp;
            опуститьToolStripMenuItem.Enabled = IsNotDown;
            bool b = false;
            bool canprob = false;
            if (c == 1)
            {
                SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;
                if (selbox != null)
                {
                    Situation selsit = ProjectLink.GetItemById(selbox.SituationId);
                    if (selsit != null)
                    {                        
                        string chname = dr.Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
                        Characteristic ch = selsit.GetFirstItemByName(chname);
                        b = ch.ParentCharacteristicId != Guid.Empty;
                        canprob = (ch.IndicatorType == IndicatorType.StepOnFail) || (ch.IndicatorType == IndicatorType.NextStep);
                    }
                }
            }
            GoToFirstParentToolStripButton.Visible = b;
            GoToFirstParentToolStripButton.Enabled = b;
            перейтиКВысшемуРодителюToolStripMenuItem.Enabled = b;
            ProbabilityToolStripButton.Visible = canprob;
        }

        /// <summary>
        /// Актуализирует данные о характеристиках указанной ситуации в датагриде характеристик
        /// </summary>
        public void UpdateCharacteristicsGrid(Situation situation)
        {
            programdatagriddirty = true;
            bool isSelectedSituation = situation == null ? true : CurrentSituationsArea.GetSituationBoxBySituation(situation) == CurrentSituationsArea.SelectedSituationBox;
            CurrentSituationsArea.HoveredNonselectedSituationBox = isSelectedSituation ? null : CurrentSituationsArea.GetSituationBoxBySituation(situation);
            CharacteristicsDataGrid.BorderStyle = BorderStyle.None;
            if (isSelectedSituation && !CharacteristicsDataGrid.Enabled)
            {
                CharacteristicsDataGrid.Enabled = true;
                RefreshSituationsArea();
            }
            int lastselectedindex = CharacteristicsDataGrid.SelectedRows.Count > 0 ? CharacteristicsDataGrid.SelectedRows[0].Index : -1;
            CharacteristicsDataGrid.Rows.Clear();
            if (situation != null)
            {
                CharacteristicsDataGrid.Visible = true;
                SituationNameTextbox.Enabled = isSelectedSituation;                
                SituationNameTextbox.Text = situation.ToString();
                SituationNameTextbox.Visible = true;
                int c = situation.ItemsCount;
                for (int i = 0; i < c; i++)
                {
                    Characteristic ch = situation.GetItemByPosition(i);
                    IndicatorType dt = ch.IndicatorType;
                    if (Indicator.IsInternalType(dt))
                        continue;
                    CharacteristicsDataGrid.Rows.Add();
                    int dc = CharacteristicsDataGrid.Rows.Count;
                    DataGridViewRow dr = CharacteristicsDataGrid.Rows[dc - 1];
                    if (ch.ParentCharacteristicId != Guid.Empty)
                    {
                        dr.DefaultCellStyle.SelectionBackColor = Color.LightCoral;
                        dr.DefaultCellStyle.SelectionForeColor = Color.Black;
                    }
                    if (ch.IndicatorType == IndicatorType.IsASituation)
                    {
                        dr.DefaultCellStyle.SelectionBackColor = Color.LightSeaGreen;
                        dr.DefaultCellStyle.SelectionForeColor = Color.Black;
                    }
                    if (ch.IndicatorLimiter != null)
                    {
                        Bitmap bt = null;
                        if ((ch.ParentCharacteristicId != Guid.Empty) && (ch.OwningSituation.IsA.GetItemById(ch.ParentCharacteristicId).IndicatorLimiter != null))
                        {//унаследованный ограничитель показателя
                            bt = SoftwareConsulting.BI11.Studio.UI.Properties.Resources.indicatorlimiter_inherited;
                        }
                        else
                        {//обычный ограничитель показателя
                            bt = SoftwareConsulting.BI11.Studio.UI.Properties.Resources.indicatorlimiter;
                        }
                        bt.MakeTransparent(Color.Magenta);
                        int ind = GetIndexOfColumn(CharacteristicsDataGridColumn.IndicatorLimiter);
                        dr.Cells[ind].Value = bt;
                        if (isSelectedSituation)
                        {
                            dr.Cells[ind].ToolTipText = Resources.BI_SITUATIONSHIERARCHY_CHARACTERISTIC_INDICATORLIMITER;
                            dr.Cells[ind].ContextMenuStrip = CharacteristicsDataGridContextMenu;
                        }
                    }
                    else
                    {
                        Bitmap bt = SoftwareConsulting.BI11.Studio.UI.Properties.Resources.emptyicon;
                        bt.MakeTransparent(Color.Magenta);
                        int ind = GetIndexOfColumn(CharacteristicsDataGridColumn.IndicatorLimiter);
                        dr.Cells[ind].Value = bt;
                        if (isSelectedSituation)
                        {
                            dr.Cells[ind].ToolTipText = Resources.BI_SITUATIONSHIERARCHY_CHARACTERISTIC_NOINDICATORLIMITER;
                            dr.Cells[ind].ContextMenuStrip = CharacteristicsDataGridContextMenu;
                        }
                    }
                    if (ch.IsMandatory)
                    {
                        Bitmap bt = SoftwareConsulting.BI11.Studio.UI.Properties.Resources.mandatory;
                        bt.MakeTransparent(Color.Magenta);
                        int ind = GetIndexOfColumn(CharacteristicsDataGridColumn.Mandatory);
                        dr.Cells[ind].Value = bt;
                        if (isSelectedSituation)
                        {
                            dr.Cells[ind].ToolTipText = Resources.BI_SITUATIONSHIERARCHY_CHARACTERISTIC_MANDATORY;
                            dr.Cells[ind].ContextMenuStrip = CharacteristicsDataGridContextMenu;
                        }
                    }
                    else
                    {
                        Bitmap bt = SoftwareConsulting.BI11.Studio.UI.Properties.Resources.emptyicon;
                        bt.MakeTransparent(Color.Magenta);
                        int ind = GetIndexOfColumn(CharacteristicsDataGridColumn.Mandatory);
                        dr.Cells[ind].Value = bt;
                        if (isSelectedSituation)
                        {
                            dr.Cells[ind].ToolTipText = Resources.BI_SITUATIONSHIERARCHY_CHARACTERISTIC_NONMANDATORY;
                            dr.Cells[ind].ContextMenuStrip = CharacteristicsDataGridContextMenu;
                        }
                    }
                    int nind = GetIndexOfColumn(CharacteristicsDataGridColumn.Name);
                    if (isSelectedSituation)
                    {
                        dr.Cells[nind].Style.ForeColor = SystemColors.WindowText;
                    }
                    else
                    {
                        dr.Cells[nind].Style.ForeColor = SystemColors.GrayText;
                    }
                    dr.Cells[nind].Value = ch.Name;
                    if (isSelectedSituation)
                    {
                        dr.Cells[nind].ContextMenuStrip = CharacteristicsDataGridContextMenu;
                        if (ch.IndicatorType == IndicatorType.IsASituation)
                        {
                            dr.Cells[nind].Style.BackColor = Color.LightBlue;
                            dr.Cells[nind].ContextMenuStrip = CharacteristicsDataGridContextMenu;
                        }
                        if (ch.ParentCharacteristicId != Guid.Empty)
                        {
                            dr.Cells[nind].Style.BackColor = Color.Pink;
                            dr.Cells[nind].ContextMenuStrip = CharacteristicsDataGridContextMenu;
                        }
                    }
                    int dind = GetIndexOfColumn(CharacteristicsDataGridColumn.Indicator);
                    DataGridViewTextBoxCell dvc_indicator = (dr.Cells[dind]) as DataGridViewTextBoxCell;
                    dvc_indicator.Style.ForeColor = isSelectedSituation ? SystemColors.WindowText : SystemColors.GrayText;
                    dvc_indicator.Value = ch.UsedIndicator.Name;
                    if (isSelectedSituation
                        && (Indicator.IsUserType(ch.IndicatorType) || Indicator.IsSituationType(ch.IndicatorType)))
                    {
                        dvc_indicator.Style.ForeColor = Color.Blue;
                        dvc_indicator.Style.Font = new Font(CharacteristicsDataGrid.DefaultCellStyle.Font, FontStyle.Underline);
                        if (Indicator.IsUserType(ch.IndicatorType))
                        {
                            dvc_indicator.ToolTipText = Resources.BI_SITUATIONSHIERARCHY_TOOLTIP_INDICATORGOTO;
                        }
                        else
                        {
                            dvc_indicator.ToolTipText = Resources.BI_SITUATIONSHIERARCHY_TOOLTIP_SITUATIONGOTO;
                        }
                        dvc_indicator.ContextMenuStrip = CharacteristicsDataGridContextMenu;
                    }
                    int vind = GetIndexOfColumn(CharacteristicsDataGridColumn.Value);
                    DataGridViewComboBoxCell dvc_value = (dr.Cells[vind]) as DataGridViewComboBoxCell;
                    if (ch.IndicatorType != IndicatorType.RulesContainer)
                    {
                        FillCharacteristicValueComboBox(dvc_value, ch);
                        SelectCharacteristicValueInComboBox(dvc_value, ch.ExpectedValue);
                        if (isSelectedSituation)
                        {
                            dvc_value.Style.ForeColor = SystemColors.WindowText;
                        }
                        else
                        {
                            dvc_value.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
                            dvc_value.Style.ForeColor = SystemColors.GrayText;
                            dvc_value.ReadOnly = true;
                        }
                    }
                    else
                    {
                        dvc_value.ReadOnly = true;
                        dvc_value.FlatStyle = FlatStyle.Flat;
                        dvc_value.Style.Font = new Font(CharacteristicsDataGrid.Font, FontStyle.Underline);                            
                        if (isSelectedSituation)
                        {
                            dvc_value.Style.ForeColor = SystemColors.MenuHighlight;
                        }
                        else
                        {
                            dvc_value.Style.ForeColor = SystemColors.GrayText;
                        }                            
                        dvc_value.Items.Add(Resources.BI_SITUATIONSHIERARCHY_CHARACTERISTIC_LINK_RULESCONTAINER);
                        dvc_value.Value = Resources.BI_SITUATIONSHIERARCHY_CHARACTERISTIC_LINK_RULESCONTAINER;
                    }
                    if (isSelectedSituation)
                    {
                        dvc_value.ContextMenuStrip = CharacteristicsDataGridContextMenu;
                    }                    
                }
            }
            else
            {
                CharacteristicsDataGrid.Visible = false;
                SituationNameTextbox.Text = "";
                SituationNameTextbox.Visible = false;
            }
            if (isSelectedSituation)
            {
                if ((lastselectedindex < CharacteristicsDataGrid.Rows.Count) && (lastselectedindex >= 0))
                {
                    CharacteristicsDataGrid.Rows[lastselectedindex].Selected = true;
                    CharacteristicsDataGrid.CurrentCell = CharacteristicsDataGrid.SelectedRows[0].Cells[CharacteristicsDataGrid.CurrentCellAddress.X];
                }
            }
            programdatagriddirty = false;
            if (isSelectedSituation)
            {
                UpdateCharacteristicsGridToolBar();
                CharacteristicsDataGrid.BorderStyle = BorderStyle.FixedSingle;
            }
            else
            {
                DataGridViewSelectedRowCollection rows = CharacteristicsDataGrid.SelectedRows;
                foreach(DataGridViewRow row in rows)
                {
                    row.Selected = false;
                }
                CharacteristicsDataGrid.Enabled = false;                
            }            
        }

        /// <summary>
        /// Производит корректную фокусировку области ситуаций без скроллирования в начало
        /// </summary>        
        public void FocusSituationsArea()
        {   
            SplitterPanel sp = splitContainer1.Panel2;
            HScrollProperties hs = sp.HorizontalScroll;
            VScrollProperties vs = sp.VerticalScroll;
            int hv = hs.Value;
            int vv = vs.Value;
            SituationsAreaPanel.Focus();
            sp.AutoScrollPosition = new Point(hv, vv);
        }

        /// <summary>
        /// Создание нового прямоугольника ситуации
        /// </summary>
        private SituationBox CreateSituationBox(int x, int y, Situation situation)
        {            
            SituationBox sitbox = CurrentSituationsArea.CreateSituationBox(x, y, situation);
            sitbox.Control.ContextMenuStrip = SituationBoxContextMenu;
            sitbox.Control.Parent = SituationsAreaPanel;
            sitbox.Control.Focus();
            sitbox.Control.SelectAll();
            RefreshMap();
            return sitbox;
        }

        /// <summary>
        /// Обработка клика по области ситуаций
        /// </summary>
        /// <param name="point"></param>
        private LinkType ProcessSituationsAreaClick(Point point, MouseButtons buttons)
        {            
            LinkType lt = LinkType.None;
            if (CurrentSituationsArea.MovementWay != Directions2D.None)
                return lt;            
            switch(CurrentSituationsArea.State)
            {
                case SituationsHierarchyState.NewSituation:
                    if (buttons == MouseButtons.Left)
                    {
                        Situation sit = ProjectLink.CreateSituation();
                        CreateSituationBox(point.X, point.Y, sit);
                    }
                    break;
                case SituationsHierarchyState.Pointer:
                    if (CurrentSituationsArea.SelectedSituationBox != null)
                    {
                        UpdateCharacteristicsGrid(null);
                    }
                    bool foundselectedline = false;
                    bool changed = false;                    
                    foreach(LinkLine ll in CurrentSituationsArea.LinkLines)
                    {
                        if (!ll.IsPointOnLine(point))
                            continue;                        
                        foundselectedline = true;
                        if (CurrentSituationsArea.SelectedLinkLine != ll)
                            changed = true;
                        CurrentSituationsArea.SelectedLinkLine = ll;
                        switch (ProjectLink.GetCharacteristicById(ProjectLink.GetLinkById(ll.RelatedLinkId).SourceCharacteristicId).IndicatorType)
                        {
                            case IndicatorType.Subsituation:
                                lt = LinkType.Subsituation;
                                break;
                            case IndicatorType.IsASituation:
                                lt = LinkType.IsA;
                                break;
                        }                        
                    }
                    if (!foundselectedline)
                    {
                        if (CurrentSituationsArea.SelectedLinkLine != null)
                        {
                            CurrentSituationsArea.SelectedLinkLine = null;
                            RefreshSituationsArea();
                        }                        
                    }
                    else
                    {                        
                        CurrentSituationsArea.ActualizeScheme(null, true);
                    }
                    if (CurrentSituationsArea.SelectedSituationBox != null)
                    {
                        changed = true;
                        CurrentSituationsArea.SelectedSituationBox = null;
                    }
                    if (CurrentSituationsArea.MultiselectedSituationBoxes != null)
                    {
                        changed = true;
                        CurrentSituationsArea.MultiselectedSituationBoxes = null;
                        CurrentSituationsArea.ActualizeScheme(null, false);
                    }
                    if (changed)
                        FocusSituationsArea();                    
                    break;
            }                                 
            return lt;
        }

        /// <summary>
        /// Отрисовка связей между ситуациями
        /// </summary>
        private void PaintLinkLines(bool isMap)
        {
            if (ProjectDescriptor.StateOfPreparation.HasFlag(PreparationStates.Deserialization) || !ProjectLink.Active)
                return;                                    
            if (CurrentSituationsArea.ItemsCount == 0)
                return; 
            ColorScheme curscheme = _CurrentSituationsArea.ProjectExplorerLink.Scheme;
            Point p1 = new Point();
            Point p2 = new Point();
            //***********************************
            //***рисуем область от незафиксированной ситуации к датагриду
            if (!isMap && (CurrentSituationsArea.HoveredNonselectedSituationBox != null))
            {
                Brush brf = null;
                switch(curscheme)
                {
                    case ColorScheme.System:
                        brf = SystemBrushes.ControlLight;
                        break;
                    case ColorScheme.Red:
                        brf = Brushes.Bisque;
                        break;
                    default:
                        Assert.Fail(Assert.Id.Assert00147);
                        break;
                }                
                p1.X = CurrentSituationsArea.HoveredNonselectedSituationBox.X;
                p1.Y = CurrentSituationsArea.HoveredNonselectedSituationBox.Y;
                p2.X = CurrentSituationsArea.HoveredNonselectedSituationBox.X;
                p2.Y = CurrentSituationsArea.HoveredNonselectedSituationBox.Y + CurrentSituationsArea.HoveredNonselectedSituationBox.Control.Height;
                Point p3 = SituationsAreaPanel.PointToClient(SituationNameTextbox.PointToScreen(new Point(CharacteristicsDataGrid.Width, CharacteristicsDataGrid.PreferredSize.Height)));
                Point p4 = SituationsAreaPanel.PointToClient(SituationNameTextbox.PointToScreen(new Point(SituationNameTextbox.Width, 0)));
                Point[] pp = new Point[4] { p1, p2, p3, p4 };                                
                _drawingPanelGraphics.FillPolygon(brf, pp, FillMode.Alternate);                
            }
            //***********************************
            Brush br = SystemBrushes.MenuHighlight;
            Pen p = new Pen(br);
            p.EndCap = LineCap.NoAnchor;
            p.Alignment = PenAlignment.Center;
            foreach(SituationBox sitbox in CurrentSituationsArea)
            {                        
                Situation sit = ProjectLink.GetItemById(sitbox.SituationId);
                if (!Assert.FailIf(sit == null, Assert.Id.Assert00148))
                    continue;
                Situation sitbylink = sit.IsA as Situation;
                if (sitbylink != null)
                {
                    //***Отрисовка связи "это"
                    Link li = ProjectLink.GetIsALinkBySituation(sit);
                    SituationBox isasitBox = CurrentSituationsArea.GetSituationBoxBySituation(sitbylink);
                    if (!Assert.FailIf((isasitBox == null) || (li == null), Assert.Id.Assert00149))
                        continue;
                    switch(curscheme)
                    {
                        case ColorScheme.System:
                            p.Brush = SystemBrushes.MenuHighlight;
                            break;
                        case ColorScheme.Red:
                            p.Brush = Brushes.Red;
                            break;
                        default:
                            Assert.Fail(Assert.Id.Assert00150);
                            break;
                    }                                        
                    p.DashStyle = DashStyle.Solid;
                    p1.X = sitbox.X;
                    p1.Y = sitbox.Y;
                    Corners gotcorner, gotcorner2;
                    p2 = isasitBox.GetNearestCorner(p1, 1, false, out gotcorner2);
                    p1 = sitbox.GetNearestCorner(p2, 1, false, out gotcorner);
                    LinkLine ll = CurrentSituationsArea.GetLinkLineByLink(li);
                    if (ll == null)
                    {
                        ll = new LinkLine( CurrentSituationsArea, li, p1, p2);
                        CurrentSituationsArea.AddLinkLine(ll);
                    }
                    else
                    {
                        ll.SourcePoint = p1;
                        ll.DestinationPoint = p2;
                    }
                    p.Width = CurrentSituationsArea.SelectedLinkLine == ll ? 4 : 2;                    
                    Rectangle rect = GeometricMethods.TwoPointsToRectangle(p1, p2);
                    if (isMap 
                        || (rect.Width == 0) && (_drawingPanelGraphics.IsVisible(p1) || _drawingPanelGraphics.IsVisible(p2)) 
                        || _drawingPanelGraphics.IsVisible(rect))
                    {
                        _drawingPanelGraphics.DrawLine(p, p1, p2);
                    }
                    if (!isMap)
                    {
                        int offsetX = 0;
                        int offsetY = 0;
                        Image isa_picture = null;
                        switch (gotcorner2)
                        {
                            case Corners.TopLeft:
                                offsetX = -7;
                                offsetY = -13;
                                switch (curscheme)
                                {
                                    case ColorScheme.System:
                                        isa_picture = LinksImages.Images["situation_isa_down_blue.png"];
                                        break;
                                    case ColorScheme.Red:
                                        isa_picture = LinksImages.Images["situation_isa_down_red.png"];
                                        break;
                                }
                                break;
                            case Corners.TopRight:
                                offsetX = -9;
                                offsetY = -13;
                                switch (curscheme)
                                {
                                    case ColorScheme.System:
                                        isa_picture = LinksImages.Images["situation_isa_down_blue.png"] ;
                                        break;
                                    case ColorScheme.Red:
                                        isa_picture = LinksImages.Images["situation_isa_down_red.png"];
                                        break;
                                }
                                break;
                            case Corners.BottomLeft:
                                offsetX = -7;
                                offsetY = -2;
                                switch (curscheme)
                                {
                                    case ColorScheme.System:
                                        isa_picture = LinksImages.Images["situation_isa_up_blue.png"];
                                        break;
                                    case ColorScheme.Red:
                                        isa_picture = LinksImages.Images["situation_isa_up_red.png"];
                                        break;
                                }
                                break;
                            case Corners.BottomRight:
                                offsetX = -8;
                                offsetY = -2;
                                switch (curscheme)
                                {
                                    case ColorScheme.System:
                                        isa_picture = LinksImages.Images["situation_isa_up_blue.png"];
                                        break;
                                    case ColorScheme.Red:
                                        isa_picture = LinksImages.Images["situation_isa_up_red.png"];
                                        break;
                                }
                                break;
                        }                        
                        p2.X += offsetX;
                        p2.Y += offsetY;
                        if (_drawingPanelGraphics.IsVisible(p2))
                            _drawingPanelGraphics.DrawImage(isa_picture, p2);                        
                    }                                                
                }                            
                if (!isMap)
                {
                    //***Отрисовка связей к подситуациям, "следующим шагам" и "шагам при неудаче"
                    foreach (Characteristic ch in sit.WalkCharacteristicsByIndicatorTypes(IndicatorType.Subsituation, IndicatorType.NextStep, IndicatorType.StepOnFail))
                    {                                                            
                        sitbylink = ch.ExpectedValue as Situation;
                        SituationBox sitbylinkBox = CurrentSituationsArea.GetSituationBoxBySituation(sitbylink);
                        if (sitbylinkBox == null)
                            continue;
                        IndicatorType dt = ch.IndicatorType;
                        p1.X = sitbox.X + sitbox.Control.Width;
                        p1.Y = sitbox.Y;                        
                        Corners gotcorner, gotcorner2;
                        p2 = sitbylinkBox.GetNearestCorner(p1, 1, dt == IndicatorType.Subsituation, out gotcorner);
                        p1 = sitbox.GetNearestCorner(p2, 1, dt != IndicatorType.Subsituation, out gotcorner2);
                        switch(curscheme)
                        {
                            case ColorScheme.System:
                                switch(dt)
                                {
                                    case IndicatorType.Subsituation:
                                        p.Brush = SystemBrushes.WindowFrame;
                                        break;
                                    case IndicatorType.NextStep:
                                        p.Brush = SystemBrushes.HotTrack;
                                        break;
                                    case IndicatorType.StepOnFail:
                                        p.Brush = Brushes.Red;
                                        break;
                                    default:
                                        Assert.Fail(Assert.Id.Assert00151);
                                        break;
                                }
                                break;
                            case ColorScheme.Red:
                                switch(dt)
                                {
                                    case IndicatorType.Subsituation:
                                        p.Brush = Brushes.Green;
                                        break;
                                    case IndicatorType.NextStep:
                                        p.Brush = Brushes.DarkSeaGreen;
                                        break;
                                    case IndicatorType.StepOnFail:
                                        p.Brush = Brushes.Sienna;
                                        break;
                                    default:
                                        Assert.Fail(Assert.Id.Assert00152);
                                        break;
                                }
                                break;
                            default:
                                Assert.Fail(Assert.Id.Assert00153);
                                break;
                        }
                        p.DashStyle = dt == IndicatorType.Subsituation ? DashStyle.Dot : DashStyle.DashDot;
                        Link li = ProjectLink.GetLinkBySourceCharacteristic(ch);
                        if (!Assert.FailIf(li == null, Assert.Id.Assert00154))
                            continue;              
                        LinkLine ll = CurrentSituationsArea.GetLinkLineByLink(li);
                        if (ll == null)
                        {
                            ll = new LinkLine(CurrentSituationsArea, li, p1, p2);
                            CurrentSituationsArea.AddLinkLine(ll);
                        }
                        else
                        {
                            ll.SourcePoint = p1;
                            ll.DestinationPoint = p2;
                        }                        
                        p.Width = CurrentSituationsArea.SelectedLinkLine == ll ? 4 : 2;                        
                        Rectangle rect = GeometricMethods.TwoPointsToRectangle(p1, p2);
                        if ((rect.Width == 0) && (_drawingPanelGraphics.IsVisible(p1) || _drawingPanelGraphics.IsVisible(p2)) 
                            || _drawingPanelGraphics.IsVisible(rect))
                        {
                            _drawingPanelGraphics.DrawLine(p, p1, p2);
                        }
                        int offsetX = -1;
                        int offsetY = -1;
                        if (gotcorner2 == Corners.TopLeft)
                        {
                            offsetX = -3;
                            offsetY = -3;
                        }
                        if (gotcorner2 == Corners.BottomLeft)
                        {
                            offsetX = -3;
                        }
                        _drawingPanelGraphics.DrawEllipse(p, p2.X + offsetX, p2.Y + offsetY, 4, 4);                        
                    }                    
                    //отрисовка проводимой в данный момент связи
                    if (CurrentSituationsArea.IsLinkCreatingProcess && sitbox.IsLinkStart)
                    {                        
                        switch(CurrentSituationsArea.State)
                        {                                
                            case SituationsHierarchyState.IsA:
                                switch(curscheme)
                                {
                                    case ColorScheme.System:
                                        p.Brush = SystemBrushes.MenuHighlight;
                                        break;                                        
                                    case ColorScheme.Red:
                                        p.Brush = Brushes.Red;
                                        break;
                                    default:
                                        Assert.Fail(Assert.Id.Assert00155);
                                        break;
                                }                                
                                p.DashStyle = DashStyle.Solid;                                
                                break;
                            case SituationsHierarchyState.Subsituation:
                                switch (curscheme)
                                {
                                    case ColorScheme.System:
                                        p.Brush = SystemBrushes.WindowFrame;
                                        break;
                                    case ColorScheme.Red:
                                        p.Brush = Brushes.Green;
                                        break;
                                    default:
                                        Assert.Fail(Assert.Id.Assert00156);
                                        break;
                                }                                
                                p.DashStyle = DashStyle.Dot;                                
                                break;
                            default:
                                Assert.Fail(Assert.Id.Assert00157);
                                break;
                        }
                        p.Width = 2;                       
                        p1.X = sitbox.X;
                        p1.Y = sitbox.Y;
                        _drawingPanelGraphics.DrawLine(p, p1, _curmouseposition);
                    }
                }                
                //*******************************************
                //на карте обозначаем ситуации точками
                if (isMap)
                {
                    Brush brf = null;
                    if (sit.ExcludedFromInference)
                    {
                        brf = Brushes.Yellow;
                    }
                    else
                    {
                        switch (curscheme)
                        {
                            case ColorScheme.System:
                                brf = Brushes.Red;
                                break;
                            case ColorScheme.Red:
                                brf = Brushes.Blue;
                                break;
                        }
                    }
                    _drawingPanelGraphics.FillRectangle(brf, sitbox.X, sitbox.Y, 2 / _scaleFactorX, 2 / _scaleFactorY);
                }
                /////////////////////////////////////////////                
            }
            //***********************************
            if (!isMap)
            {            
                //чистим лишние линии связей                        
                List<LinkLine> llsToDelete = new List<LinkLine>();
                foreach(LinkLine ll in CurrentSituationsArea.LinkLines)
                {                            
                    Link li = ProjectLink.GetLinkById(ll.RelatedLinkId);
                    if (li == null)
                        llsToDelete.Add(ll);                    
                }
                foreach (LinkLine ll in llsToDelete)
                {
                    CurrentSituationsArea.DeleteLinkLine(ll);
                }
            }                        
        }

        /// <summary>
        /// Прорисовка прямоугольника множественного выделения в области ситуаций
        /// </summary>
        /// <param name="e"></param>
        private void RedrawMultiSelection()
        {
            if (!CurrentSituationsArea.IsMultiselect)
                return;            
            Brush br = SystemBrushes.HotTrack;                
            Pen p = new Pen(br);                              
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
            int X1;
            int X2;
            int Y1;
            int Y2;
            if (CurrentSituationsArea.MultiselectionStartPoint.X < CurrentSituationsArea.MultiselectionEndPoint.X)
            {
                X1 = CurrentSituationsArea.MultiselectionStartPoint.X;
                X2 = CurrentSituationsArea.MultiselectionEndPoint.X;
            }
            else
            {
                X2 = CurrentSituationsArea.MultiselectionStartPoint.X;
                X1 = CurrentSituationsArea.MultiselectionEndPoint.X;
            }
            if (CurrentSituationsArea.MultiselectionStartPoint.Y < CurrentSituationsArea.MultiselectionEndPoint.Y)
            {
                Y1 = CurrentSituationsArea.MultiselectionStartPoint.Y;
                Y2 = CurrentSituationsArea.MultiselectionEndPoint.Y;
            }
            else
            {
                Y2 = CurrentSituationsArea.MultiselectionStartPoint.Y;
                Y1 = CurrentSituationsArea.MultiselectionEndPoint.Y;
            }
            Rectangle rect = new Rectangle(X1, Y1, X2 - X1, Y2 - Y1);
            _drawingPanelGraphics.DrawRectangle(p, rect);            
        }

        /// <summary>
        /// Скроллирует область ситуаций к указанному прямоугольнику ситуации
        /// </summary>
        /// <param name="situationBox"></param>
        public void ScrollToSituationBox(SituationBox situationBox)
        {
            if (situationBox == null)
                return;            
            TextBox tb = situationBox.Control;
            SplitterPanel pn = splitContainer1.Panel2;
            Rectangle rc = pn.ClientRectangle;
            if ((tb.Left < rc.Left) || (tb.Right > rc.Right) || (tb.Top < rc.Top) || (tb.Bottom > rc.Bottom))
            {                    
                pn.ScrollControlIntoView(tb as Control);                    
            }            
        }

        /// <summary>
        /// Обновление панели области ситуаций/карты
        /// </summary>
        private void UpdateDrawingPanel(Graphics graphics, bool isMap)
        {
            _scaleFactorX = ((float)MapPanel.Width) / ((float)SituationsAreaPanel.Width);
            _scaleFactorY = ((float)MapPanel.Height) / ((float)SituationsAreaPanel.Height);
            _drawingPanelGraphics = graphics;
            _drawingPanelGraphics.SmoothingMode = isMap ? SmoothingMode.HighSpeed : _smoothMode;            
            PaintLinkLines(isMap);
            if (!isMap)
            {
                RedrawMultiSelection();
            }
        }

        /// <summary>
        /// Обновление родителя у текстбокса ситуации
        /// </summary>
        /// <param name="situationBox"></param>
        public void UpdateTextBoxParent(SituationBox situationBox)
        {
            Assert.FailIfNot(ProjectDescriptor.StateOfPreparation.HasFlag(PreparationStates.Deserialization), Assert.Id.Assert00158);
            situationBox.Control.Parent = SituationsAreaPanel;//для десериализации
        }
        
        /// <summary>
        /// Реализация перемещения объекта-прямоугольника ситуации
        /// </summary>
        /// <param name="situationBox"></param>
        public bool MoveSituationBox(SituationBox situationBox, int situationBoxOffsetX, int situationBoxOffsetY, bool recursively)
        {
            TextBox tb = situationBox.Control;
            int newleft = tb.Left + situationBoxOffsetX;
            int newtop = tb.Top + situationBoxOffsetY;
            bool inrect = true;
            bool inrectothers = true;
            if (newleft < 0)
            {
                newleft = 0;
                inrect = false;
            }
            if (newtop < 0)
            {
                newtop = 0;
                inrect = false;
            }
            int maxright = SituationsAreaPanel.Width - tb.Width - 5;
            if (newleft > maxright )
            {
                newleft = maxright;
                inrect = false;
            }
            int maxbottom = SituationsAreaPanel.Height - tb.Height - 5;
            if (newtop > maxbottom)
            {
                newtop = maxbottom;
                inrect = false;
            }            
            if (!recursively)
            {
                IHierarchy<SituationBox> mssb = CurrentSituationsArea.MultiselectedSituationBoxes;
                if ((mssb != null) && mssb.Contains(situationBox))
                {
                    foreach(SituationBox sitbox2 in mssb)
                    {                        
                        if (sitbox2 != situationBox)
                        {                            
                            inrectothers = inrect && inrectothers && MoveSituationBox(sitbox2, situationBoxOffsetX, situationBoxOffsetY, true);                            
                        }
                    }                 
                }
            }
            if (inrectothers && ((tb.Left != newleft) || (tb.Top != newtop)))            
            {            
                tb.Left = newleft;
                tb.Top = newtop;
                situationBox.X = tb.Left;
                situationBox.Y = tb.Top;                
                if (!recursively)
                {                    
                    CheckMoveState(newleft, newtop);
                    if (CurrentSituationsArea.MovementWay != Directions2D.None)
                    {
                        ScrollSituationsAreaByMouseDown();
                        RefreshSituationsAreaImmediately();
                    }
                    else
                    {
                        RefreshSituationsArea();                        
                    }
                }                
            }
            return (inrect || CurrentSituationsArea.MultiselectedSituationBoxes == null || ((CurrentSituationsArea.MultiselectedSituationBoxes != null) && (CurrentSituationsArea.MultiselectedSituationBoxes.ItemsCount == 0))) && inrectothers;
        }

        /// <summary>
        /// Правильное обновление карты (умное)
        /// </summary>
        public void RefreshMap()
        {
            DateTime d = DateTime.Now;
            if (d.Subtract(_mapLastRefreshTime).TotalMilliseconds >= _currentMapRefreshInterval)
            {                
                RefreshMapImmediately();
                return;
            }            
            if (!_mapSuspendedRefresh) //таймер еще не запущен
            {
                _mapLastRefreshTime = d;
                _mapSuspendedRefresh = true;                    
                _mapSuspendedRefreshTimer.Start();
            }            
        }

        /// <summary>
        /// Немедленное обновление карты
        /// </summary>
        private void RefreshMapImmediately()
        {
            _mapSuspendedRefreshTimer.Stop();                        
            _mapLastRefreshTime = DateTime.Now;
            MapPanel.Refresh();
            DateTime timeAfterRefresh = DateTime.Now;
            double time = timeAfterRefresh.Subtract(_mapLastRefreshTime).TotalMilliseconds;
            if (time > SituationsArea.MapMaxRefreshTime) //рисовали слишком долго
            {
                int newinterval = Convert.ToInt32(Math.Round(SituationsArea.MapRefreshInterval * ((float)time / (float)SituationsArea.MapMaxRefreshTime)));
                if ((newinterval - _currentMapRefreshInterval) > SituationsArea.RefreshIntervalMaxOffset)//значимая разница интервалов
                {
                    _currentMapRefreshInterval = newinterval;
                    _mapSuspendedRefreshTimer.Interval = newinterval;                    
                }
            }
            else
            {
                //рисуем быстро
                if ((_currentMapRefreshInterval - SituationsArea.MapRefreshInterval) > SituationsArea.RefreshIntervalMaxOffset)
                {
                    //интервал стоит значимо больше отпимального,
                    //значит приводим к оптимальному
                    _currentMapRefreshInterval = SituationsArea.MapRefreshInterval;
                }
            }
            _mapSuspendedRefresh = false;
        }

        /// <summary>
        /// Правильное обновление области ситуаций (умное)
        /// </summary>
        public void RefreshSituationsArea()
        {
            DateTime d = DateTime.Now;     
            if (d.Subtract(_DSLastRefreshTime).TotalMilliseconds >= _currentSituationsAreaRefreshInterval)
            {                
                RefreshSituationsAreaImmediately();
                return;
            }            
            if (!_SASuspendedRefresh) //таймер еще не запущен
            {
                _DSLastRefreshTime = d;
                _SASuspendedRefresh = true;
                _SASuspendedRefreshTimer.Start();
            }            
        }

        /// <summary>
        /// Немедленное обновление области ситуаций
        /// </summary>
        private void RefreshSituationsAreaImmediately()
        {
            _SASuspendedRefreshTimer.Stop();                        
            _DSLastRefreshTime = DateTime.Now;
            SituationsAreaPanel.Refresh();            
            DateTime timeAfterRefresh = DateTime.Now;
            double time = timeAfterRefresh.Subtract(_DSLastRefreshTime).TotalMilliseconds;
            if (time > SituationsArea.SituationsAreaMaxRefreshTime) //рисовали слишком долго
            {
                int newinterval = Convert.ToInt32(Math.Round(SituationsArea.SituationsAreaRefreshInterval * ((float)time / (float)SituationsArea.SituationsAreaMaxRefreshTime)));
                if ((newinterval - _currentSituationsAreaRefreshInterval) > SituationsArea.RefreshIntervalMaxOffset)//значимая разница интервалов
                {
                    _currentSituationsAreaRefreshInterval = newinterval;
                    _SASuspendedRefreshTimer.Interval = newinterval;
                }
            }
            else
            {
                //рисуем быстро
                if ((_currentSituationsAreaRefreshInterval - SituationsArea.SituationsAreaRefreshInterval) > SituationsArea.RefreshIntervalMaxOffset)
                {
                    //интервал стоит значимо больше отпимального,
                    //значит приводим к оптимальному
                    _currentSituationsAreaRefreshInterval = SituationsArea.SituationsAreaRefreshInterval;
                }
            }
            _SASuspendedRefresh = false;
        }

        /// <summary>
        /// Возвращает размеры РП
        /// </summary>
        /// <returns></returns>
        public Size SituationsAreaSize
        {
            get
            {
                return SituationsAreaPanel.Size;
            }
        }

        /// <summary>
        /// Фокусирует панель области ситуаций, наплевав на скроллинг
        /// </summary>
        public void FocusSituationsAreaWithBrokenScrolling()
        {
            SituationsAreaPanel.Focus();
        }

        /// <summary>
        /// Вызывает диалог редактирования описания выделенного события
        /// </summary>
        public void ShowEditEventDialog()
        {
            SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;
            if (selbox != null)
            {
                Situation selsit = ProjectLink.GetItemById(selbox.SituationId);
                SituationDescriptionDialog sdd = new SituationDescriptionDialog(selsit);
                sdd.ShowDialog();
            }
        }

        /// <summary>
        /// Удаление выбранных ситуаций
        /// </summary>
        public void DeleteSelectedSituations()
        {
            Control cl = SituationBoxContextMenu.SourceControl;
            SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;            
            if (selbox != null)
            {
                cl = cl == null ? selbox.Control : cl;                
                if ((CurrentSituationsArea.MultiselectedSituationBoxes != null) && (CurrentSituationsArea.MultiselectedSituationBoxes.Contains(selbox)))
                {
                    DeleteSelectedGroup();
                }
                else
                {
                    ReadScrollInfo(); //почему-то после удаления ситуации сбивается скролл
                    if (DeleteSelectedSituation(cl as TextBox, true))
                        UpdateCharacteristicsGrid(null);
                    SetScrollInfo();
                }
            }
            else
            {
                if (CurrentSituationsArea.MultiselectedSituationBoxes != null)
                    DeleteSelectedGroup();                
            }
            RefreshSelectedSituationActionsAbilities();
        }

        /// <summary>
        /// Удаление выделенной ситуации
        /// </summary>
        private bool DeleteSelectedSituation(TextBox textBox,bool toRefreshDS)
        {
            bool deleted = false;
            SituationBox sitbox = CurrentSituationsArea.GetSituationBoxByTextBox(textBox);
            if (Assert.FailIfNot(sitbox != null, Assert.Id.Assert00159))
            {
                Situation sit = ProjectLink.GetItemById(sitbox.SituationId);
                DialogResult d = DialogResult.OK;                
                bool toPrompt = CurrentSituationsArea.ProjectExplorerLink.CurrentSettings.CharacteristicsBlockingAbility;
                INamedHierarchy<Situation> sits = new NamedHierarchy<Situation>();
                if (toPrompt)
                {                    
                    foreach(Situation sit2 in ProjectLink.WalkAllChildSituations(sit))
                    {
                        if (sit2.InheritedCharacteristicsCount() > 0)
                        {
                            d = ShowLinkDeletingDialog(sits);
                            break;
                        }
                    }
                }
                if (d == DialogResult.OK)
                {
                    try
                    {                        
                        ProjectLink.Delete(sit);                        
                        ProjectLink.Modified = true;                        
                        sitbox.Kill(toRefreshDS);                                               
                        deleted = true;
                        if (toPrompt)
                        {
                            foreach(Situation sit2 in sits)
                            {                                
                                int c = sit2.ItemsCount;
                                for (int i = 0; i < c; i++)
                                {
                                    Characteristic ch = sit2.GetItemByPosition(i);
                                    if (ch.BlockedWhileLinkDeleting)
                                    {
                                        ch.BlockedWhileLinkDeleting = false;
                                    }
                                }
                            }
                        }
                    }
                    catch (BISituationsHierarchySituationUsedException ex)
                    {
                        GeneralMethods.ShowUserError(ex.Message);
                    }
                }
            }            
            return deleted;
        }

        /// <summary>
        /// Удаление выделенной связи
        /// </summary>
        private void DeleteSelectedLink()
        {
            LinkLine ll = CurrentSituationsArea.SelectedLinkLine;
            if (ll == null)
                return;            
            Link li = ProjectLink.GetLinkById(ll.RelatedLinkId);
            Characteristic sourcech = ProjectLink.GetCharacteristicById(li.SourceCharacteristicId);
            Situation sourcesit = sourcech.OwningSituation;
            DialogResult d = DialogResult.OK;
            bool toPrompt = CurrentSituationsArea.ProjectExplorerLink.CurrentSettings.CharacteristicsBlockingAbility;
            INamedHierarchy<Situation> sits = new NamedHierarchy<Situation>();
            if (toPrompt)
            {
                if ((sourcech.IndicatorType == IndicatorType.IsASituation) && (sourcesit.InheritedCharacteristicsCount() > 0))
                {
                    sits.Add(sourcesit);
                    d = ShowLinkDeletingDialog(sits);
                }
            }
            if (d == DialogResult.OK)
            {
                ProjectLink.DeleteLink(li);
                if (sourcech.IndicatorType != IndicatorType.IsASituation)
                {
                    sourcech.SetExpectedValue(null);
                    //02.09.2010 само в SetExpectedValue теперь делается 
                    //только там не все характеристики обновляются,
                    //а лишь измененная.. быть может приведет к косякам
                    //(например, при обновлении ограничителей значений)
                    //sit.UpdateInheritedCharacteristicsOfChilds(ch.Id,ch.Name,InheritedCharacteristicParts.All,false);
                }
                else
                {
                    sourcesit.SetIsA(null);
                }                    
                RefreshSituationsArea();
                RefreshMap();
                if (sits.ItemsCount == 1) //может быть либо 0 (когда связи ситуация-подситуация), либо 1 (когда связи "это")
                {
                    foreach(Characteristic ch2 in sourcesit)
                    {                            
                        if (ch2.BlockedWhileLinkDeleting)
                            ch2.BlockedWhileLinkDeleting = false;                        
                    }
                }
            }                     
        }

        /// <summary>
        /// Удаление выделенной группы ситуаций
        /// </summary>
        private void DeleteSelectedGroup()
        {            
            foreach(SituationBox sitbox in CurrentSituationsArea.MultiselectedSituationBoxes)
            {
                DeleteSelectedSituation(sitbox.Control, false);
            }
            CurrentSituationsArea.MultiselectedSituationBoxes = null;
            RefreshSituationsArea();
            UpdateCharacteristicsGrid(null);
            RefreshMap();
        }

        /// <summary>
        /// Удаление сфокусированного объекта области ситуаций
        /// </summary>
        private void DeleteSelectedLinkOrSituationBoxesGroup()
        {
            if ((CurrentSituationsArea.MultiselectedSituationBoxes != null) && (CurrentSituationsArea.MultiselectedSituationBoxes.ItemsCount > 0))
            {
                DeleteSelectedGroup();
                return;
            }            
            DeleteSelectedLink();
        }

        /// <summary>
        /// Вощвращает колонку ячейки датагрида характеристик
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        private CharacteristicsDataGridColumn GetColumnOfCell(DataGridViewCell cell)
        {
            int col = cell.ColumnIndex;
            DataGridViewColumnCollection dc = CharacteristicsDataGrid.Columns;
            string cname = dc[col].Name;
            switch (cname)
            {
                case "indicatorlimiter_column":
                    return CharacteristicsDataGridColumn.IndicatorLimiter;
                case "mandatory_column":
                    return CharacteristicsDataGridColumn.Mandatory;
                case "name_column":
                    return CharacteristicsDataGridColumn.Name;
                case "indicator_column":
                    return CharacteristicsDataGridColumn.Indicator;
                default:
                    return CharacteristicsDataGridColumn.Value;
            }                                                
        }

        /// <summary>
        /// Возвращает индекс колонки датагрида характеристик
        /// </summary>
        private int GetIndexOfColumn(CharacteristicsDataGridColumn column)
        {
            DataGridViewColumnCollection dc = CharacteristicsDataGrid.Columns;
            int c = dc.Count;
            for (int i = 0; i < c; i++)
            {
                string cname = dc[i].Name;
                if ((cname == "indicatorlimiter_column") && (column == CharacteristicsDataGridColumn.IndicatorLimiter)
                    || (cname == "mandatory_column") && (column == CharacteristicsDataGridColumn.Mandatory)
                    || (cname == "name_column") && (column == CharacteristicsDataGridColumn.Name)
                    || (cname == "indicator_column") && (column == CharacteristicsDataGridColumn.Indicator)
                    || (cname == "value_column") && (column == CharacteristicsDataGridColumn.Value))
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// Обрабатывает изменения в DataGrid'е характеристик
        /// </summary>
        /// <param name="cell"></param>
        private void ProcessCharacteristicsGridValueChange(DataGridViewCell cell)
        {
            if (programdatagriddirty)
                return;
            if (GetColumnOfCell(cell) != CharacteristicsDataGridColumn.Value)
                return;            
            programdatagriddirty = true;
            object memory = cell.Value;
            CharacteristicsDataGrid.EndEdit();
            programdatagriddirty = false;                
            string chname = CharacteristicsDataGrid.Rows[cell.RowIndex].Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
            Situation selsit = ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId);                    
            Characteristic ch = selsit.GetFirstItemByName(chname);
            if (!Indicator.IsSituationType(ch.IndicatorType))
            {
                try
                {
                    if (GeneralMethods.IsNullString(cell.Value))
                    {
                        ch.SetExpectedValue(null);
                    }
                    else
                    {
                        switch (ch.IndicatorType)
                        {
                            case IndicatorType.Boolean:
                                ch.SetExpectedValue(bool.Parse(cell.Value as string));
                                break;
                            case IndicatorType.Integer:
                                ch.SetExpectedValue(int.Parse(cell.Value.ToString(), CultureInfo.CurrentCulture));
                                break;
                            case IndicatorType.Float:
                                ch.SetExpectedValue(float.Parse(cell.Value.ToString(), CultureInfo.CurrentCulture));
                                break;
                            default:
                                ch.SetExpectedValue(cell.Value);
                                break;
                        }
                    }
                    if (GeneralMethods.IsNull(ch.ExpectedValue))
                    {
                        ///это надо для обновления
                        ///при наследовании UNIQUE                                                                
                        if (selsit.InheritanceWay == InheritanceKind.Unique)
                        {
                            programdatagriddirty = true;
                            cell.Value = Constants.NullDoesNotMatterString;
                            programdatagriddirty = false;
                            UpdateCharacteristicsGrid(selsit);
                        }
                    }
                    //TODO: на уровень ядра надо так-то обновление детишек унести
                    //02.09.2010 унёс:) selsit.UpdateInheritedCharacteristicsOfChilds(ch.Id, ch.Name, InheritedCharacteristicParts.ExpectedValue, false);
                }
                catch (BISituationsHierarchyException ex)
                {
                    GeneralMethods.ShowUserError(ex.Message);
                    cell.Value = memory;
                    programdatagriddirty = true;
                    CharacteristicsDataGrid.EndEdit();
                    programdatagriddirty = false;
                }
            }
            else
            {                        
                Situation sitbylink = null;
                if (!GeneralMethods.IsNullString(cell.Value))
                {
                    string sitname = (cell.Value as string).Substring(1, (cell.Value as string).IndexOf(">", StringComparison.CurrentCulture) - 1);
                    sitbylink = ProjectLink.GetFirstItemByName(sitname);
                }
                try
                {
                    if (ch.IndicatorType == IndicatorType.IsASituation)
                    {
                        selsit.SetIsA(sitbylink);
                    }
                    else
                    {
                        ch.SetExpectedValue(sitbylink, ch.IndicatorType == IndicatorType.Subsituation); //не надо только шаги при ошибке и следующие шаги прокачивать
                        /*02.09.2010 if (ch.IndicatorType == IndicatorType.Subsituation)
                        {
                            selsit.UpdateInheritedCharacteristicsOfChilds(ch.Id,ch.Name,InheritedCharacteristicParts.ExpectedValue,false);
                        }*/
                    }
                    if ((ch.IndicatorType != IndicatorType.NextStep) && (ch.IndicatorType != IndicatorType.StepOnFail))
                    {                                
                        RefreshSituationsArea();
                    }
                    else
                    {
                        if (sitbylink.ExcludedFromInference)
                        {
                            GeneralMethods.ShowWarning(Resources.BI_SITUATIONSHIERARCHY_LINKINGSITUATIONSTOEXCLUDEDSITUATION);                                    
                        }
                    }
                    UpdateCharacteristicsGrid(ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId));
                }
                catch (BISituationsHierarchyException ex)
                {
                    GeneralMethods.ShowUserError(ex.Message);
                    cell.Value = memory;
                    programdatagriddirty = true;
                    CharacteristicsDataGrid.EndEdit();
                    programdatagriddirty = false;
                }                        
            }                                            
        }

        /// <summary>
        /// Обновляет размер рабочего пространства
        /// </summary>
        public void UpdateSituationsAreaSize()
        {
            if (CurrentSituationsArea.Scaling)
                return;               
            SplitterPanel sp = splitContainer1.Panel2;
            int oldxc = sp.HorizontalScroll.Value + sp.Width / 2;                
            int oldyc = sp.VerticalScroll.Value + sp.Height / 2;                
            int newxc = Convert.ToInt32(Math.Round(oldxc * CurrentSituationsArea.ScalingFactorForRectangleX));
            int newyc = Convert.ToInt32(Math.Round(oldyc * CurrentSituationsArea.ScalingFactorForRectangleY));
            SituationsAreaPanel.Width = Convert.ToInt32(Math.Round(SituationsAreaPanel.Width * CurrentSituationsArea.ScalingFactorForRectangleX));
            SituationsAreaPanel.Height = Convert.ToInt32(SituationsAreaPanel.Height * CurrentSituationsArea.ScalingFactorForRectangleY);
            RefreshSituationsArea();
            sp.AutoScrollPosition = new Point(newxc - sp.Width / 2, newyc - sp.Height / 2);
            RefreshMap();            
        }

        /// <summary>
        /// Проставляет чекбокс масштаба в соответствии с установленным
        /// </summary>
        public void UpdateScaleInfo()
        {
            SituationsHierarchyScale sc = CurrentSituationsArea.Scale;
            панорамаToolStripMenuItem.Checked = false;
            оченьмелкийToolStripMenuItem.Checked = false;
            мелкийToolStripMenuItem1.Checked = false;
            уменьшенныйToolStripMenuItem.Checked = false;
            обычныйToolStripMenuItem1.Checked = false;
            switch(sc)
            {
                case SituationsHierarchyScale.Normal:
                    обычныйToolStripMenuItem1.Checked = true;
                    break;
                case SituationsHierarchyScale.Less:
                    уменьшенныйToolStripMenuItem.Checked = true;
                    break;
                case SituationsHierarchyScale.Little:
                    мелкийToolStripMenuItem1.Checked = true;
                    break;
                case SituationsHierarchyScale.VeryLittle:
                    оченьмелкийToolStripMenuItem.Checked = true;
                    break;
                case SituationsHierarchyScale.Panorama:
                    панорамаToolStripMenuItem.Checked = true;
                    break;
            }                        
            RefreshMap();
        }        

        /// <summary>
        /// Уменьшает масштаб рабочего пространстваы
        /// </summary>
        public bool DoScaleLess()
        {
            if (CurrentSituationsArea.DoScaleLess())
            {
                UpdateScaleInfo();
                return true;
            }
            return false;
        }

        /// <summary>
        /// Увеличивает масштаб рабочего пространства
        /// </summary>
        public bool DoScaleLarger()
        {
            if (CurrentSituationsArea.DoScaleLarger())
            {
                UpdateScaleInfo();
                return true;
            }
            return false;            
        }

        /// <summary>
        /// Включает или выключает обновление визуальной информации в области ситуаций        
        /// </summary>
        /// <param name="switchOn"></param>
        public void SetSituationsAreaPanelLayout(bool switchOn)
        {
            if (switchOn)
            {                                
                SituationsAreaPanel.ResumeLayout(true);
            }
            else
            {
                SituationsAreaPanel.SuspendLayout();
            }
        }

        /// <summary>
        /// Устанавливает масштаб области ситуаций
        /// </summary>
        public void ScaleSituationsArea(SituationsHierarchyScale scale)
        {            
            CurrentSituationsArea.Scale = scale;
            if (!ProjectDescriptor.StateOfPreparation.HasFlag(PreparationStates.Serialization))
                UpdateScaleInfo();            
        }        

        /// <summary>
        /// Добавление новой пользовательской характеристики
        /// </summary>
        private void AddCustomCharacteristic(IIndicator characteristicIndicator)
        {                        
            SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;                        
            Situation selsit = ProjectLink.GetItemById(selbox.SituationId);
            if (!Assert.FailIf(selsit == null, Assert.Id.Assert00160))
                return;
            object obj = characteristicIndicator.GetIndicatorValueByPosition(0).Value;//верхнее допустимое значение показателя устанавливается как текущее
            string newname = Characteristic.DefaultName;
            Characteristic ch = new Characteristic(newname, characteristicIndicator, obj, selsit, true, obj, ProjectLink, true, false);
            selsit.Add(ch); 
            selsit.UpdateInheritedCharacteristicsOfChilds(ch.Id, ch.Name, InheritedCharacteristicParts.All, false);                                           
            UpdateCharacteristicsGrid(selsit);
            CharacteristicsDataGrid.Rows[FindIndexOfDataGridRowByCharacteristicName(ch.Name)].Selected = true;
            CharacteristicsDataGrid.CurrentCell = CharacteristicsDataGrid.SelectedRows[0].Cells[CharacteristicsDataGrid.CurrentCellAddress.X];
            UpdateCharacteristicsGridToolBar();                                    
        }

        /// <summary>
        /// Добавление новой системной характеристики
        /// </summary>
        private void AddSpecialCharacteristic(IndicatorType indicatorType)
        {                        
            SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;                        
            Situation selsit = ProjectLink.GetItemById(selbox.SituationId);
            if (!Assert.FailIf(selsit == null, Assert.Id.Assert00161))
                return;     
            object stval = null;
            if (indicatorType == IndicatorType.RulesContainer)
            {
                RulesContainer rc = new RulesContainer(ProjectLink);
                ProjectLink.AddRulesContainer(rc);
                stval = rc.Id;
            }
            string newname = Characteristic.DefaultName;
            Characteristic ch = new Characteristic(newname, ProjectLink.GetSpecialIndicator(indicatorType, true), stval, selsit, true, stval, ProjectLink, true, false);
            selsit.Add(ch);
            if ((indicatorType != IndicatorType.NextStep) && (indicatorType != IndicatorType.StepOnFail))
            {
                selsit.UpdateInheritedCharacteristicsOfChilds(ch.Id, ch.Name, InheritedCharacteristicParts.All, false);
            }
            UpdateCharacteristicsGrid(selsit);
            CharacteristicsDataGrid.Rows[FindIndexOfDataGridRowByCharacteristicName(ch.Name)].Selected = true;
            CharacteristicsDataGrid.CurrentCell = CharacteristicsDataGrid.SelectedRows[0].Cells[CharacteristicsDataGrid.CurrentCellAddress.X];
            UpdateCharacteristicsGridToolBar();            
        }

        /// <summary>
        /// Удаление выделенной характеристики
        /// </summary>
        private void DeleteCharacteristic()
        {
            SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;
            if (selbox == null)
                return;            
            Situation selsit = ProjectLink.GetItemById(selbox.SituationId);                
            DataGridViewRow dr = CharacteristicsDataGrid.SelectedRows[0];
            string chname = dr.Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
            Characteristic ch = selsit.GetFirstItemByName(chname);
            if (!Assert.FailIf(ch == null, Assert.Id.Assert00162))
                return;            
            try
            {
                selsit.Delete(ch);
            }
            catch (BISituationsHierarchyCharacteristicCantBeDeletedException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
            }
            UpdateCharacteristicsGrid(selsit);
            RefreshSituationsArea();                 
        }

        /// <summary>
        /// Возвращает индекс строки датагрида связанной с указанной характеристикой
        /// </summary>
        /// <param name="name"></param>
        private int FindIndexOfDataGridRowByCharacteristicName(string name)
        {
            int c = CharacteristicsDataGrid.Rows.Count;
            int nind = GetIndexOfColumn(CharacteristicsDataGridColumn.Name);
            for (int i = 0; i < c; i++)
            {
                DataGridViewRow dr = CharacteristicsDataGrid.Rows[i];
                if ((dr.Cells[nind].Value as string) == name)
                    return i;                
            }
            return -1;
        }

        /// <summary>
        /// Поднятие выделенной характеристики на 1 позицию выше
        /// </summary>
        private void UpCharacteristic()
        {
            DataGridViewRow dr = CharacteristicsDataGrid.SelectedRows[0];
            if (dr == null)
                return;            
            Situation sit = ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId);                
            string chname = dr.Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
            Characteristic ch = sit.GetFirstItemByName(chname);
            int i = sit.GetPositionOfItem(ch);
            if (i >= 2) //есть куда повышать
            {
                Characteristic ch2 = sit.GetItemByPosition(i - 1);
                sit.SwapItems(ch, ch2);
                UpdateCharacteristicsGrid(sit);
                CharacteristicsDataGrid.Rows[FindIndexOfDataGridRowByCharacteristicName(ch.Name)].Selected = true;
                CharacteristicsDataGrid.CurrentCell = CharacteristicsDataGrid.SelectedRows[0].Cells[CharacteristicsDataGrid.CurrentCellAddress.X];
                UpdateCharacteristicsGridToolBar();                    
            }            
        }

        /// <summary>
        /// Спуск выделенной характеристики на 1 позицию ниже
        /// </summary>
        private void DownCharacteristic()
        {
            DataGridViewRow dr = CharacteristicsDataGrid.SelectedRows[0];
            if (dr == null)
                return;            
            Situation sit = ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId);                
            string chname = dr.Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
            Characteristic ch = sit.GetFirstItemByName(chname);                
            int c = sit.ItemsCount;
            int i = sit.GetPositionOfItem(ch);
            if (i <= (c-1)) //есть куда понижать
            {
                Characteristic ch2 = sit.GetItemByPosition(i + 1);
                sit.SwapItems(ch, ch2);
                UpdateCharacteristicsGrid(sit);
                CharacteristicsDataGrid.Rows[FindIndexOfDataGridRowByCharacteristicName(ch.Name)].Selected = true;
                CharacteristicsDataGrid.CurrentCell = CharacteristicsDataGrid.SelectedRows[0].Cells[CharacteristicsDataGrid.CurrentCellAddress.X];
                UpdateCharacteristicsGridToolBar();                    
            }            
        }

        /// <summary>
        /// Отображает диалог фиксации элементов измерений куба
        /// </summary>
        public FixedDimensionItemsPointer ShowFixedDimensionItemsDialog(FixedDimensionItemsPointer fixedDimensionItems)
        {
            FixDimensionItemsDialog fid = new FixDimensionItemsDialog(ProjectLink, fixedDimensionItems);
            if (fid.ShowDialog() == DialogResult.OK)
            {
                return fid.FixedDimensionItems;
            }
            return fixedDimensionItems;
        }

        /// <summary>
        /// Определяет видим ли указанный прямоугольник или его часть на РП
        /// </summary>
        /// <param name="rectangle"></param>
        /// <returns></returns>
        public bool IsRectangleFullVisible(Rectangle rectangle)
        {          
            SplitterPanel sp = splitContainer1.Panel2;
            HScrollProperties hs = sp.HorizontalScroll;
            VScrollProperties vs = sp.VerticalScroll;
            Rectangle viewRect = new Rectangle(hs.Value, vs.Value, sp.Width - 20, sp.Height - 20); //20 - это на скроллбары
            return viewRect.Contains(rectangle);
        }

        /// <summary>
        /// Обработка клика по свойствам характеристик в датагриде
        /// </summary>
        private void ProcessCharacteristicsGridClick(int rowIndex, int columnIndex)
        {
            if (rowIndex == -1) //бывает -1 если ткнули на заголовки
                return;                  
            string chname = CharacteristicsDataGrid.Rows[rowIndex].Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
            SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;                
            Situation selsit = ProjectLink.GetItemById(selbox.SituationId);                
            Characteristic ch = selsit.GetFirstItemByName(chname);
            if (columnIndex == GetIndexOfColumn(CharacteristicsDataGridColumn.Mandatory)) //обязательная/необязательная
            {
                DialogResult dia = DialogResult.Cancel;
                if (ch.IsMandatory)
                {
                    try
                    {
                        ch.SetIsMandatory(false);
                    }
                    catch (BISituationsHierarchyException ex)
                    {
                        GeneralMethods.ShowUserError(ex.Message);
                    }
                    UpdateCharacteristicsGrid(ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId));
                }
                if (!ch.IsMandatory)
                {                        
                    dia = ShowUncertaintyValueDialog(ch);                        
                    if (dia == DialogResult.Abort)
                    {
                        ch.SetIsMandatory(true);
                        UpdateCharacteristicsGrid(ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId));
                    }
                }
                if (ch.IsMandatory || dia == DialogResult.OK)
                {
                    selsit.UpdateInheritedCharacteristicsOfChilds(ch.Id, ch.Name, InheritedCharacteristicParts.MandatoryToggle | InheritedCharacteristicParts.UncertaintyValue, false);
                }
                return;
            }
            if (columnIndex == GetIndexOfColumn(CharacteristicsDataGridColumn.IndicatorLimiter))
            {
                try
                {
                    if (ch.IndicatorLimiter == null)
                    {
                        ch.CreateIndicatorLimiter(true);
                        UpdateCharacteristicsGrid(ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId));
                    }
                    DialogResult dia = ShowIndicatorLimiterDialog(ch);
                    if (dia == DialogResult.Abort)
                    {
                        ch.DeleteIndicatorLimiter(true);
                    }
                }
                catch (BISituationsHierarchyException ex)
                {
                    GeneralMethods.ShowUserError(ex.Message);
                }
                UpdateCharacteristicsGrid(ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId));
                return;
            }
            if (columnIndex == GetIndexOfColumn(CharacteristicsDataGridColumn.Indicator))
            {
                if (Indicator.IsSituationType(ch.IndicatorType))
                {
                    Situation sitbylink = ch.ExpectedValue as Situation;
                    if (sitbylink != null)
                    {
                        CurrentSituationsArea.GotoSituationBoxBySituation(sitbylink);
                    }
                }
                if (Indicator.IsUserType(ch.IndicatorType))
                {
                    ShowIndicatorEditorDialog(ch.UsedIndicator);
                }
                return;
            }
            if (columnIndex == GetIndexOfColumn(CharacteristicsDataGridColumn.Value))
            {
                if (ch.IndicatorType == IndicatorType.RulesContainer)
                {
                    ShowOrHideRulesContainerEditor(ch, true);
                }
                else
                {
                    CharacteristicsDataGrid.Rows[rowIndex].Cells[columnIndex].Selected = true;
                    CharacteristicsDataGrid.CurrentCell = CharacteristicsDataGrid.Rows[rowIndex].Cells[columnIndex];
                    CharacteristicsDataGrid.BeginEdit(true);
                    CharacteristicsDataGrid.EditMode = DataGridViewEditMode.EditOnEnter;                        
                }
                return;
            }            
        }       

        /// <summary>
        /// Входит в режим/выходит из режима редактирования контейнера правил
        /// </summary>        
        /// <param name="characteristicWithRulesContainer">характеристика, в которой контейнер правил (null => перегрузили проект и редактируемой характеристики уже не существует)</param>
        /// <param name="toShow">входим в режим (true) или выходим(false)</param>
        public void ShowOrHideRulesContainerEditor(Characteristic characteristicWithRulesContainer, bool toShow)
        {
            Text = toShow ? Resources.BI_SITUATIONSHIERARCHY_RULESCONTAINER_EDITORCAPTION : Resources.BI_SITUATIONSHIERARCHY_CAPTION;
            Icon = toShow ? SoftwareConsulting.BI11.Studio.UI.Properties.Resources.limresults : SoftwareConsulting.BI11.Studio.UI.Properties.Resources.office_building1;
            ControlBox = !toShow;
            if (characteristicWithRulesContainer != null)
            {
                _editingRulesContainerId = (Guid)(characteristicWithRulesContainer.ExpectedValue);
                _editingCharacteristicWithRulesContainerId = characteristicWithRulesContainer.Id;
            }
            else
            {            
                toShow = false;
            }
            _inRulesContainerEditor = toShow;
            if (toShow)
                ReadScrollInfo();            
            SituationsAreaPanel.Visible = !toShow;            
            splitContainer1.Panel1Collapsed = toShow;            
            if (!toShow)
                SetScrollInfo();                        
            RulesContainerEditorPanel.Visible = toShow;
            //приходится вручную положение всех контролов указывать, потому 
            //что тупые глюки с изменением их расположения при анчорах
            //когда скрываем область ситуаций
            SplitterPanel sp = splitContainer1.Panel2;
            backLIMcheckbox.Left = label1.Left;
            backLIMcheckbox.Top = sp.Height - backLIMcheckbox.Height - 8;
            RulesContainerAimCombo.Left = backLIMcheckbox.Left;
            RulesContainerAimCombo.Top = backLIMcheckbox.Top - RulesContainerAimCombo.Height - 8;
            RulesContainerAimLabel.Left = RulesContainerAimCombo.Left;
            RulesContainerAimLabel.Top = RulesContainerAimCombo.Top - RulesContainerAimLabel.Height - 1;
            RulesContainerOKButton.Left = sp.Width - RulesContainerOKButton.Width - 11;
            RulesContainerOKButton.Top = RulesContainerAimCombo.Top;
            RulesPanel.Width = RulesContainerOKButton.Left + RulesContainerOKButton.Width - RulesPanel.Left;
            RulesPanel.Height = RulesContainerAimLabel.Top - 8 - RulesPanel.Top;
            //убираем все пункты тулбара
            toolStrip1.Visible = !toShow;                  
            Situation sit = null;
            if (toShow)
            {
                RulesContainer rc = ProjectLink.GetRulesContainerById(_editingRulesContainerId);                
                _selectedRuleIndex = -1;
                RefreshRulesContainer(rc);
                return;
            }            
            if (characteristicWithRulesContainer != null)
            {
                sit = characteristicWithRulesContainer.OwningSituation;
                UpdateCharacteristicsGrid(sit);
            }                        
        }

        /// <summary>
        /// Отображает диалог поиска ситуации
        /// </summary>
        private void ShowFindSituationDialog()
        {
            (new FindObjectDialog(_CurrentSituationsArea.ProjectExplorerLink, new MetadataObjectsVisibleTypes { Kind = MetadataObjectKind.Situation, All = false })).ShowDialog();
        }

        /// <summary>
        /// Отображает диалог блокировки характеристик при удалении связи
        /// </summary>
        private DialogResult ShowLinkDeletingDialog(INamedHierarchy<Situation> situations)
        {
            LinkDeletingDialog ld = new LinkDeletingDialog(situations, CurrentSituationsArea.ProjectExplorerLink);
            return ld.ShowDialog();
        }

        /// <summary>
        /// Отображает диалог редактирования ограничителя показателя для выбранной характеристики
        /// </summary>
        private DialogResult ShowIndicatorLimiterDialog(Characteristic characteristic)
        {
            IndicatorLimiterDialog indlims = new IndicatorLimiterDialog(ProjectLink, characteristic);
            return indlims.ShowDialog();            
        }        

        /// <summary>
        /// Отображает диалог выбора значения неопределенности для выбранной характеристики
        /// </summary>
        private static DialogResult ShowUncertaintyValueDialog(Characteristic characteristic)
        {
            UncertaintyValueDialog uvd = new UncertaintyValueDialog(characteristic);
            return uvd.ShowDialog();
        }

        /// <summary>
        /// Отображает диалог редактирования показателя
        /// </summary>
        private void ShowIndicatorEditorDialog(IIndicator indicator)
        {
            //10.12.2010 CurrentSituationsArea.IsMultiselectByCtrl = false;//т.к. Dialog вызывается по нажатии Ctrl+D, а отлавливание прямоугольником ситуации отпускания Ctrl уже не срабатывает, т.к. открылся диалог и управление в нем
            CurrentSituationsArea.ProjectExplorerLink.OpenObject(indicator.Descriptor);
            SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;
            Situation sit = selbox == null ? null : ProjectLink.GetItemById(selbox.SituationId);            
            UpdateCharacteristicsGrid(sit);
        }

        private void SubsituationCharacteristicDropDownClick(object sender, EventArgs e)
        {
            AddSpecialCharacteristic(IndicatorType.Subsituation);
        }

        private void RulesContainerCharacteristicDropDownClick(object sender, EventArgs e)
        {
            AddSpecialCharacteristic(IndicatorType.RulesContainer);
        }

        private void TableCharacteristicDropDownClick(object sender, EventArgs e)
        {
            AddSpecialCharacteristic(IndicatorType.Table);
        }

        private void ActionSetCharacteristicDropDownClick(object sender, EventArgs e)
        {
            AddSpecialCharacteristic(IndicatorType.ActionSet);
        }

        private void CubeCharacteristicDropDownClick(object sender, EventArgs e)
        {
            AddSpecialCharacteristic(IndicatorType.DateAndFactCorrelations);
        }

        private void BoolCharacteristicDropDownClick(object sender, EventArgs e)
        {
            AddSpecialCharacteristic(IndicatorType.Boolean);
        }

        private void NextStepCharacteristicDropDownClick(object sender, EventArgs e)
        {
            AddSpecialCharacteristic(IndicatorType.NextStep);
        }

        private void StepOnFailCharacteristicDropDownClick(object sender, EventArgs e)
        {
            AddSpecialCharacteristic(IndicatorType.StepOnFail);
        }
        
        private void CharacteristicDropDownClick(object sender,EventArgs e)
        {
            string dname = (sender as ToolStripItem).Text;
            AddCustomCharacteristic(ProjectLink.RepositoryLink.GetObjectDescriptorByLabel(dname, MetadataObjectKind.Indicator).Bind() as IIndicator);
        }

        /// <summary>
        /// Обновление списка доступных показателей
        /// </summary>
        private void UpdateIndicatorsList(ToolStripItemCollection menuCollection)
        {            
            menuCollection.Clear();
            ToolStripItem pr = null;            
            pr = menuCollection.Add(Characteristic.SubsituationCaption);
            pr.Click += new EventHandler(SubsituationCharacteristicDropDownClick);
            pr = menuCollection.Add(Characteristic.RulesContainerCaption);
            pr.Click += new EventHandler(RulesContainerCharacteristicDropDownClick);
            pr = menuCollection.Add(Characteristic.ActionsetCaption);
            pr.Click += new EventHandler(ActionSetCharacteristicDropDownClick);
            pr = menuCollection.Add(Characteristic.TableCaption);
            pr.Click += new EventHandler(TableCharacteristicDropDownClick);
            pr = menuCollection.Add(Characteristic.CubeCaption);
            pr.Click += new EventHandler(CubeCharacteristicDropDownClick);
            pr = menuCollection.Add(Characteristic.BoolCaption);
            pr.Click += new EventHandler(BoolCharacteristicDropDownClick);
            pr = menuCollection.Add(Characteristic.NextStepCaption);
            pr.Click += new EventHandler(NextStepCharacteristicDropDownClick);
            pr = menuCollection.Add(Characteristic.StepOnFailCaption);
            pr.Click += new EventHandler(StepOnFailCharacteristicDropDownClick);
            menuCollection.Add("-");
            bool hasuserindicators = false;
            foreach(IMetadataObjectDescriptor desc in ProjectLink.RepositoryLink.GetObjectsDescriptors(MetadataObjectKind.Indicator))
            {                
                if (Indicator.IsUserType((IndicatorType)desc.Subkind))
                {
                    IIndicator ind = desc.Bind() as IIndicator;
                    if (ind.GetIndicatorValuesCount() > 1)
                    {
                        ToolStripItem ti = menuCollection.Add(ind.Label);
                        ti.Click += new EventHandler(CharacteristicDropDownClick);
                        hasuserindicators = true;
                    }
                }
            }
            if (!hasuserindicators)
            {
                ToolStripItem ti = AddCharacteristicToolStripDropDownButton.DropDownItems.Add("<" + Resources.BI_SITUATIONSHIERARCHY_NOINDICATORS + ">");
                ti.ForeColor = SystemColors.InactiveCaptionText;
            }
        }

        /// <summary>
        /// Вводит имя характеристики в режим редактирования
        /// </summary>
        private void StartCharacteristicRenaming()
        {
            DataGridViewSelectedRowCollection chs = CharacteristicsDataGrid.SelectedRows;
            int c = chs.Count;
            if (c != 1)
                return;            
            DataGridViewCell dvc = CharacteristicsDataGrid.Rows[chs[0].Index].Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)];
            dvc.Selected = true;
            CharacteristicsDataGrid.CurrentCell = dvc;
            CharacteristicsDataGrid.BeginEdit(false);            
        }

        /// <summary>
        /// Множественное выделение на РП
        /// </summary>
        private void FinishMultiselection()
        {
            if (!CurrentSituationsArea.IsMultiselect)
                return;
            if (CurrentSituationsArea.MultiselectionStartPoint.Equals(CurrentSituationsArea.MultiselectionEndPoint))
                return;            
            CurrentSituationsArea.IsMultiselect = false;                    
            Rectangle multRect = GeometricMethods.TwoPointsToRectangle(CurrentSituationsArea.MultiselectionStartPoint, CurrentSituationsArea.MultiselectionEndPoint);
            IHierarchy<SituationBox> sitboxes = new Hierarchy<SituationBox>();
            foreach(SituationBox sitbox in CurrentSituationsArea)
            {                        
                TextBox tb = sitbox.Control;                        
                Rectangle tbRect = new Rectangle(tb.Left, tb.Top, tb.Width, tb.Height);
                if (multRect.IntersectsWith(tbRect))
                    sitboxes.Add(sitbox);                
            }
            CurrentSituationsArea.MultiselectedSituationBoxes = sitboxes;
            CurrentSituationsArea.ActualizeScheme(sitboxes, false);
            RefreshSituationsAreaImmediately();
            SituationBox selbox = CurrentSituationsArea.SelectedSituationBox;
            Situation selsit = selbox == null ? null : ProjectLink.GetItemById(selbox.SituationId);
            UpdateCharacteristicsGrid(selsit);
        }

        /// <summary>
        /// Подготавливает список связей в кнопке выбора связей
        /// </summary>
        private void PrepareLinksList()
        {
            int c = AllLinksToolStripDropDownButton1.DropDownItems.Count;
            for (int i = c - 1; i > 5; i--)
            {
                AllLinksToolStripDropDownButton1.DropDownItems.RemoveAt(i);
            }
            c = ProjectLink.LinksCount();
            if (c == 0)
            {
                AllLinksToolStripDropDownButton1.DropDownItems.Add(Resources.BI_SITUATIONSHIERARCHY_LINKS_EMPTYLIST);
                return;
            }            
            for (int i = 0; i < c; i++)
            {
                Link l = ProjectLink.GetLinkByPosition(i);
                string ls = "";
                Characteristic ch = ProjectLink.GetCharacteristicById(l.SourceCharacteristicId);
                if (ch != null)
                {
                    ls = ch.OwningSituation.ToString() + "." + ch.ToString() + " -> ";
                    Situation sit2 = ch.ExpectedValue as Situation;
                    ls += sit2 == null ? Constants.NullDoesNotMatterString : sit2.Name;                    
                }
                else
                {
                    ls = Resources.BI_SITUATIONSHIERARCHY_LINKS_LIST_FAILED + " (" + l.SourceCharacteristicId.ToString() + ")";
                }
                AllLinksToolStripDropDownButton1.DropDownItems.Add(ls);
            }            
        }

        /// <summary>
        /// Переименование характеристики
        /// </summary>
        private void RenameCharacteristic(int row, int column)
        {
            if (programdatagriddirty)
                return;
            if (column != GetIndexOfColumn(CharacteristicsDataGridColumn.Name)) //имя характеристики
                return;            
            Situation sit = ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId);                    
            Characteristic ch = sit.GetFirstItemByName(_lastcharacteristicname);
            string newcharacteristicname = CharacteristicsDataGrid.Rows[row].Cells[column].Value as string;
            if (_lastcharacteristicname.Equals(newcharacteristicname))
                return;            
            try
            {
                if (ch.ParentCharacteristicId != Guid.Empty)
                {
                    throw new BISituationsHierarchyCharacteristicCantBeRenamedException(null);                                
                }
                ch.SetName(newcharacteristicname);
                sit.UpdateInheritedCharacteristicsOfChilds(ch.Id, ch.Name, InheritedCharacteristicParts.Name, false);                
            }
            catch (BISituationsHierarchyCharacteristicCantBeRenamedException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
                ch.SetName(_lastcharacteristicname);
                CharacteristicsDataGrid.Rows[row].Cells[column].Value = _lastcharacteristicname;
                return;
            }
            _lastcharacteristicname = ch.Name;
        }

        /// <summary>
        /// Обработка клика по линку в списке линков
        /// </summary>
        /// <param name="item"></param>
        private void ProcessLinksListClick(ToolStripItem item)
        {
            int index = AllLinksToolStripDropDownButton1.DropDownItems.IndexOf(item);
            if ((index > 5) && (item.Text != Resources.BI_SITUATIONSHIERARCHY_LINKS_EMPTYLIST))
            {
                Link l = ProjectLink.GetLinkByPosition(index - 6);               
                CurrentSituationsArea.GotoLinkLineByLink(l);
            }
        }

        /// <summary>
        /// Геттер контекстного меню прямоугольника ситуации
        /// </summary>
        /// <returns></returns>
        public ContextMenuStrip GetSituationBoxContext
        {
            get
            {
                return SituationBoxContextMenu;
            }
        }

        /// <summary>
        /// Входит в режим редактирования названия ситуации
        /// </summary>
        private void StartRenamingOfSelectedSituation()
        {
            TextBox tb = CurrentSituationsArea.SelectedSituationBox.Control;
            tb.Focus();
            tb.SelectAll();
        }        

        /// <summary>
        /// Возвращает/устанавливает текст подсказки области ситуаций
        /// </summary>        
        public string SituationsAreaTip
        {
            get
            {
                return _CurrentSituationsArea.ProjectExplorerLink.SituationsAreaTip;
            }
            set
            {                
                _CurrentSituationsArea.ProjectExplorerLink.SituationsAreaTip = value;
            }
        }

        /// <summary>
        /// Переименование ситуации через датагрид характеристик
        /// </summary>
        private void RenameSituationThroughCharacteristicsDataGrid()
        {
            SituationBox sitbox = CurrentSituationsArea.SelectedSituationBox;
            if (sitbox != null)
            {
                string s = SituationNameTextbox.Text;
                TextBox control = sitbox.Control;
                control.Text = s;
                control.Size = control.PreferredSize;
                sitbox.TryRename();
            }
        }       

        /// <summary>
        /// Изменяет тип связи с "это" на ситуация-подситуация и наоборот
        /// </summary>
        private void SwitchLinkType()
        {            
            Link l = ProjectLink.GetLinkById(CurrentSituationsArea.SelectedLinkLine.RelatedLinkId);            
            Characteristic ch_ = ProjectLink.GetCharacteristicById(l.SourceCharacteristicId);
            Situation sit = ch_.OwningSituation;
            IndicatorType dt = ch_.IndicatorType;
            try
            {
                switch (dt)
                {
                    case IndicatorType.Subsituation:
                        Situation subsit = ch_.ExpectedValue as Situation;
                        sit.Delete(ch_);
                        sit.SetIsA(subsit);
                        break;
                    case IndicatorType.IsASituation:
                        Situation isasit = sit.IsA as Situation;
                        sit.SetIsA(null);
                        sit.RemoveLinksToDeadSituations();
                        Characteristic ch = new Characteristic(Characteristic.DefaultName, ProjectLink.GetSpecialIndicator(IndicatorType.Subsituation, true), isasit, sit, true, null, ProjectLink, false, false);
                        sit.Add(ch);
                        sit.UpdateInheritedCharacteristicsOfChilds(Guid.Empty, "", InheritedCharacteristicParts.All, false);
                        break;
                    default:
                        Assert.Fail(Assert.Id.Assert00163);
                        return;
                }
            }
            catch (BISituationsHierarchyException ex)
            {
                GeneralMethods.ShowUserError(ex.Message);
            }                    
            RefreshSituationsArea();    
        }

        /// <summary>
        /// Обновляет информацию о последнем состоянии имени характеристики
        /// </summary>
        /// <param name="row"></param>
        /// <param name="column"></param>
        private void UpdateLastCharacteristicName(int row, int column)
        {
            if (column == GetIndexOfColumn(CharacteristicsDataGridColumn.Name))
            {
                DataGridViewCell cell = CharacteristicsDataGrid.Rows[row].Cells[column];
                _lastcharacteristicname = cell.Value as string;                
            }
        }

        /// <summary>
        /// Реализует скроллирование РП по зажатой кнопки мыши у границы
        /// </summary>
        private void ScrollSituationsAreaByMouseDown()
        {            
            Directions2D ms = CurrentSituationsArea.MovementWay;
            if (ms == Directions2D.None)
                return;            
            SplitterPanel sp = splitContainer1.Panel2;
            HScrollProperties hs = sp.HorizontalScroll;
            VScrollProperties vs = sp.VerticalScroll;
            int newx = hs.Value;
            int newy = vs.Value;            
            while (true)
            {                
                switch (ms)
                {
                    case Directions2D.DownLeft:
                    case Directions2D.UpLeft:
                    case Directions2D.Left:
                        newx = hs.Value - SituationsArea.ScrollByMouseDown;
                        newx = newx < 0 ? 0 : newx;                        
                        switch (ms)
                        {
                            case Directions2D.UpLeft:                                                            
                                ms = Directions2D.Up;
                                continue;                                
                            case Directions2D.DownLeft:                                
                                ms = Directions2D.Down;
                                continue;                         
                        }
                        break;
                    case Directions2D.DownRight:
                    case Directions2D.UpRight:
                    case Directions2D.Right:
                        newx = hs.Value + SituationsArea.ScrollByMouseDown;
                        newx = newx > hs.Maximum ? hs.Maximum : newx;                        
                        switch (ms)
                        {
                            case Directions2D.UpRight:                                
                                ms = Directions2D.Up;
                                continue;
                            case Directions2D.DownRight:                                
                                ms = Directions2D.Down;
                                continue;                            
                        }
                        break;
                    case Directions2D.Up:
                        newy = vs.Value - SituationsArea.ScrollByMouseDown;
                        newy = newy < 0 ? 0 : newy;                        
                        break;
                    case Directions2D.Down:
                        newy = vs.Value + SituationsArea.ScrollByMouseDown;
                        newy = newy > vs.Maximum ? vs.Maximum : newy;                        
                        break;
                }                
                break;
            }
            _smoothMode = SmoothingMode.HighSpeed;
            sp.AutoScrollPosition = new Point(newx, newy);
            RefreshMap();
            _smoothMode = SmoothingMode.HighQuality;            
        }

        /// <summary>
        /// Исключает ситуацию из логического вывода или включает
        /// </summary>
        /// <param name="toInclude">true - включить, false - исключить</param>
        /// <param name="recursively">true - всю ветвь начиная с выделенной ситуации, false - только выделенную ситуацию</param>
        private void IncludeOrExcludeSelectedSituation(bool toInclude, bool recursively)
        {            
            Situation sit = ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId);
            bool noLinkingSituations = true;
            if (!recursively)
            {
                sit.ExcludedFromInference = !toInclude;
                noLinkingSituations = toInclude || (!ProjectLink.FindSituationsLinkingFromNextStepOrStepOnFail(sit.Id));
            }
            else
            {
                noLinkingSituations = ProjectLink.IncludeOrExcludeSituationsBranch(sit, toInclude) || toInclude;
            }            
            CurrentSituationsArea.ActualizeScheme(null, false);
            RefreshMap();
            if (!noLinkingSituations)
            {
                ReadScrollInfo();
                GeneralMethods.ShowWarning(Resources.BI_SITUATIONSHIERARCHY_LINKINGSITUATIONSTOEXCLUDEDSITUATION);                
                SetScrollInfo();
            }
        }

        /// <summary>
        /// Отрисовывает карту
        /// </summary>
        /// <param name="graphics"></param>
        private void UpdateMapPanel(Graphics graphics)
        {
            if (_scaleFactorX != 0)
            {                
                GraphicsContainer gc = graphics.BeginContainer();
                graphics.ScaleTransform(_scaleFactorX, _scaleFactorY);
                UpdateDrawingPanel(graphics, true);                    
                graphics.EndContainer(gc);
                Pen p = new Pen(SystemColors.InfoText, 1);
                SplitterPanel sp = splitContainer1.Panel2;
                int x = sp.HorizontalScroll.Value;
                int y = sp.VerticalScroll.Value;
                float w = sp.Width;
                float h = sp.Height;
                int scaledX = Convert.ToInt32(Math.Round(x * _scaleFactorX));
                int scaledY = Convert.ToInt32(Math.Round(y * _scaleFactorY));
                _mapWindowW = Convert.ToInt32(Math.Round(w * _scaleFactorX));
                _mapWindowH = Convert.ToInt32(Math.Round(h * _scaleFactorY));
                graphics.DrawRectangle(p, scaledX, scaledY, _mapWindowW, _mapWindowH);                
            }
        }

        /// <summary>
        /// Выделяет характеристику с указанными координатами
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void SelectCharacteristicByMousePosition(int x, int y)
        {
            Point p = CharacteristicsDataGrid.PointToClient(new Point(x, y));
            DataGridView.HitTestInfo ht = CharacteristicsDataGrid.HitTest(p.X, p.Y);
            DataGridViewSelectedRowCollection sr = CharacteristicsDataGrid.SelectedRows;
            foreach(DataGridViewRow row in sr)
            {
                row.Selected = false;                
            }
            CharacteristicsDataGrid.Rows[ht.RowIndex].Selected = true;
        }

        /// <summary>
        /// Осуществляет проверку на возможность скроллировния РП путем зажатия клавиши мыши
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void CheckMoveState(int x, int y)
        {
            SplitterPanel sp = splitContainer1.Panel2;
            HScrollProperties hs = sp.HorizontalScroll;
            VScrollProperties vs = sp.VerticalScroll;
            int rightborder = sp.Width + hs.Value;
            int leftborder = hs.Value;
            int topborder = vs.Value;
            int bottomborder = sp.Height + vs.Value;
            bool sidecursor = false;
            while (true)
            {
                if ((x >= (rightborder - SituationsArea.MouseSituationDistance)) && (rightborder < SituationsAreaPanel.Width))
                {
                    if (CurrentSituationsArea.MovementWay != Directions2D.Right)
                    {
                        CurrentSituationsArea.MovementWay = Directions2D.Right;
                    }
                    sidecursor = true;
                    break;
                }                
                if ((x <= (leftborder + SituationsArea.MouseSituationDistance)) && (leftborder > 0))
                {
                    if (CurrentSituationsArea.MovementWay != Directions2D.Left)
                    {
                        CurrentSituationsArea.MovementWay = Directions2D.Left;
                    }
                    sidecursor = true;
                }
                break;
            }
            while (true)
            {
                if ((y >= (bottomborder - SituationsArea.MouseSituationDistance)) && (bottomborder < SituationsAreaPanel.Height))
                {
                    sidecursor = true;
                    while (true)
                    {                        
                        if (CurrentSituationsArea.MovementWay.HasFlag(Directions2D.Right))
                        {
                            if (CurrentSituationsArea.MovementWay != Directions2D.DownRight)
                            {
                                CurrentSituationsArea.MovementWay = Directions2D.DownRight;
                                SituationsAreaPanel.Cursor = Cursors.SizeNWSE;
                            }                            
                            break;
                        }                        
                        if (CurrentSituationsArea.MovementWay.HasFlag(Directions2D.Left))
                        {
                            if (CurrentSituationsArea.MovementWay != Directions2D.DownLeft)
                            {
                                CurrentSituationsArea.MovementWay = Directions2D.DownLeft;
                                SituationsAreaPanel.Cursor = Cursors.SizeNESW;
                            }                            
                            break;
                        }                        
                        if (CurrentSituationsArea.MovementWay != Directions2D.Down)
                        {
                            CurrentSituationsArea.MovementWay = Directions2D.Down;
                        }                        
                        break;
                    }
                    break;
                }                
                if ((y <= (topborder + SituationsArea.MouseSituationDistance)) && (topborder > 0))
                {
                    if (CurrentSituationsArea.MovementWay == Directions2D.Right)
                    {
                        if (CurrentSituationsArea.MovementWay != Directions2D.UpRight)
                        {
                            CurrentSituationsArea.MovementWay = Directions2D.UpRight;
                            SituationsAreaPanel.Cursor = Cursors.SizeNESW;
                        }
                        sidecursor = true;
                    }
                    else
                    {
                        if (CurrentSituationsArea.MovementWay == Directions2D.Left)
                        {
                            if (CurrentSituationsArea.MovementWay != Directions2D.UpLeft)
                            {
                                CurrentSituationsArea.MovementWay = Directions2D.UpLeft;
                                SituationsAreaPanel.Cursor = Cursors.SizeNWSE;
                            }
                            sidecursor = true;
                        }
                        else
                        {
                            if (CurrentSituationsArea.MovementWay != Directions2D.Up)
                            {
                                CurrentSituationsArea.MovementWay = Directions2D.Up;
                            }
                            sidecursor = true;
                        }
                    }
                }
                break;
            }
            if (!sidecursor)
            {
                if (CurrentSituationsArea.MovementWay != Directions2D.None)
                {
                    CurrentSituationsArea.MovementWay = Directions2D.None;
                    UpdateMouseCursor();
                }
            }
            Cursor c = SituationsAreaPanel.Cursor;
            switch (CurrentSituationsArea.MovementWay)
            {
                case Directions2D.Down:
                case Directions2D.Up:
                    if (c != Cursors.NoMoveVert)
                    {
                        SituationsAreaPanel.Cursor = Cursors.NoMoveVert;
                    }
                    break;
                case Directions2D.Left:
                case Directions2D.Right:
                    if (c != Cursors.NoMoveHoriz)
                    {
                        SituationsAreaPanel.Cursor = Cursors.NoMoveHoriz;
                    }
                    break;
            }
        }

        /// <summary>
        /// Переходит к ситуации с наивысшим родителем характеристики
        /// </summary>
        private void GoToCharacteristicFirstParent()
        {
            SituationBox sitbox = CurrentSituationsArea.SelectedSituationBox;
            if (sitbox != null)
            {
                Situation sit = ProjectLink.GetItemById(sitbox.SituationId);
                if (sit != null)
                {
                    DataGridViewRow dr = CharacteristicsDataGrid.SelectedRows[0];
                    string chname = dr.Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
                    Characteristic ch = sit.GetFirstItemByName(chname);
                    if (Assert.FailIfNot(ch != null, Assert.Id.Assert00164))
                    {
                        Characteristic ch2 = ch;
                        while (ch != null)
                        {
                            ch2 = ch;
                            ch = ProjectLink.GetCharacteristicById(ch.ParentCharacteristicId);
                        }
                        Situation sit2 = ch2.OwningSituation;
                        CurrentSituationsArea.GotoSituationBoxBySituation(sit2);
                    }                    
                }
            }
        }

        /// <summary>
        /// Порождает дочернюю ситуацию
        /// </summary>
        private void BurnChildSituation()
        {
            SituationBox sitbox = CurrentSituationsArea.SelectedSituationBox;
            Situation sit2 = ProjectLink.CreateChildSituation(ProjectLink.GetItemById(sitbox.SituationId));
            int x = sitbox.X;
            int y = sitbox.Y;
            int h = sitbox.Control.Height;
            y += 2 * h;
            bool toDown = y < (SituationsAreaPanel.Height - h - 1) ? true : false;
            if (!toDown)
            {
                y -= 4 * h;
            }
            SituationBox sitbox2 = CreateSituationBox(x, y, sit2);
            int l = 0;
            int step = 1;            
            while (l < 2 * h)
            {
                int coef = toDown ? 1 : -1;
                MoveSituationBox(sitbox2, 0, coef * step, false);
                l += step;                
            }            
        }

        /// <summary>
        /// Выполняет скроллирование по карте
        /// </summary>
        /// <param name="mouseEvent"></param>
        private void ExecuteMapScrolling(MouseEventArgs mouseEvent)
        {
            if (_mapscrolling)
            {
                int x = mouseEvent.X - _mapWindowW / 2;
                int y = mouseEvent.Y - _mapWindowH / 2;
                x = x >= 0 ? x : 0;
                y = y >= 0 ? y : 0;
                SplitterPanel sp = splitContainer1.Panel2;
                int newx = System.Convert.ToInt32(System.Math.Round(x / _scaleFactorX));
                int newy = System.Convert.ToInt32(System.Math.Round(y / _scaleFactorY));
                HScrollProperties hs = sp.HorizontalScroll;
                VScrollProperties vs = sp.VerticalScroll;
                newx = newx <= hs.Maximum ? newx : hs.Maximum;
                newy = newy <= vs.Maximum ? newy : vs.Maximum;                
                if ((newx != hs.Value) || (newy != vs.Value))
                {
                    sp.AutoScrollPosition = new Point(newx, newy);
                    RefreshMap();
                }
            }
        }

        /// <summary>
        /// Центрирует РП на произвольную ситуацию
        /// </summary>
        /// <param name="situationBox"></param>
        public void CenterSituationBox(SituationBox situationBox)
        {
            int xc = situationBox.X + situationBox.Control.Width / 2;
            int yc = situationBox.Y + situationBox.Control.Height / 2;
            SplitterPanel sp = splitContainer1.Panel2;
            HScrollProperties hs = sp.HorizontalScroll;
            VScrollProperties vs = sp.VerticalScroll;
            int newx = xc - sp.Width / 2;
            int newy = yc - sp.Height / 2;
            newx = newx >= 0 ? newx : 0;
            newx = newx <= hs.Maximum ? newx : hs.Maximum;
            newy = newy >= 0 ? newy : 0;
            newy = newy <= vs.Maximum ? newy : vs.Maximum;
            sp.AutoScrollPosition = new Point(newx, newy);
            RefreshMap();
        }

        /// <summary>
        /// Центрирует РП на выбранную ситуацию
        /// </summary>
        public void CenterSelectedSituation()
        {
            SituationBox sitbox = CurrentSituationsArea.SelectedSituationBox;
            if (sitbox == null)
            {                                
                foreach(SituationBox sitbox2 in CurrentSituationsArea.MultiselectedSituationBoxes)
                {
                    sitbox = sitbox2;
                    break;
                }             
            }
            if (sitbox != null)
            {
                CenterSituationBox(sitbox);                
            }
        }

        /// <summary>
        /// Центрирует РП на центр РП
        /// </summary>
        public void CenterSituationsArea()
        {
            SplitterPanel sp = splitContainer1.Panel2;
            int newx = sp.HorizontalScroll.Maximum / 2 - sp.Width / 2;
            int newy = sp.VerticalScroll.Maximum / 2 - sp.Height / 2;
            sp.AutoScrollPosition = new Point(newx, newy);
            RefreshMap();
        }

        /// <summary>
        /// Перерисовывает РП и, если надо, реализует скроллирование по зажатой кнопки мыши у границы
        /// </summary>
        /// <param name="graphics"></param>
        private void RepaintSituationsAreaAndScroll(Graphics graphics)
        {
            UpdateDrawingPanel(graphics, false);
            if (_mousebuttonPressing)
            {
                ScrollSituationsAreaByMouseDown();
            }
        }

        /// <summary>
        /// Подготавливает контекстное меню РП в зависимости от ситуации
        /// </summary>
        private void PrepareSituationsAreaContextMenu(LinkType linkType)
        {
            удалитьСвязьToolStripMenuItem.Visible = CurrentSituationsArea.SelectedLinkLine != null;
            изменитьТипНаследованияToolStripMenuItem.Visible = (CurrentSituationsArea.SelectedLinkLine != null) && (linkType == LinkType.IsA);
            ИзменитьТипСвязиНаЭтоToolStripMenuItem.Visible = (CurrentSituationsArea.SelectedLinkLine != null) && (linkType == LinkType.Subsituation);
            ИзменитьТипСвязиНаСитуацияПодситуацияToolStripMenuItem.Visible = (CurrentSituationsArea.SelectedLinkLine != null) && (linkType == LinkType.IsA);
            ДобавитьСитуациюToolStripMenuItem.Visible = CurrentSituationsArea.SelectedLinkLine == null;
            указательToolStripMenuItem1.Checked = CurrentSituationsArea.State == SituationsHierarchyState.Pointer;
            СвязьЭтоToolStripMenuItem.Checked = CurrentSituationsArea.State == SituationsHierarchyState.IsA;
            НоваяСитуацияToolStripMenuItem.Checked = CurrentSituationsArea.State == SituationsHierarchyState.NewSituation;
            СвязьСитуацияПодситуацияToolStripMenuItem.Checked = CurrentSituationsArea.State == SituationsHierarchyState.Subsituation;
            указатьСитуациюСледующийШагToolStripMenuItem.Checked = CurrentSituationsArea.State == SituationsHierarchyState.NextStep;
            указатьСитуациюШагПриНеудачеToolStripMenuItem.Checked = CurrentSituationsArea.State == SituationsHierarchyState.StepOnFail;
        }

        /// <summary>
        /// Инициализирует РП
        /// </summary>
        private void InitializeSituationsArea()
        {
            CurrentSituationsArea.State = SituationsHierarchyState.Pointer;         
            SituationsAreaPanel.MouseWheel+=new MouseEventHandler(SituationsArea_MouseWheel);
            ShowOrHideRulesContainerEditor(null, false);
            _editingRulesContainerId = Guid.Empty;            
        }

        /// <summary>
        /// Обработчик прокрутки колеса мышки над РП
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SituationsArea_MouseWheel(object sender, MouseEventArgs e)
        {
            RefreshMap();
        }

        private void SituationsHierarchyForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            Hide();
            e.Cancel = !ReallyClose;
        }

        private void SituationsHierarchyForm_Load(object sender, EventArgs e)
        {
            InitializeSituationsArea();                  
        }

        private void createSituationToolStripButton_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.NewSituation);
        }

        private void PointerToolStripButton_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.Pointer);
        }

        private void SituationsArea_MouseClick(object sender, MouseEventArgs e)
        {            
            ProcessSituationsAreaClick(e.Location,e.Button);           
        }

        private void SituationsArea_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clip = new Region(e.ClipRectangle);
            RepaintSituationsAreaAndScroll(e.Graphics);            
        }

        private void удалитьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DeleteSelectedSituations();
        }

        private void указательToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.Pointer);
        }

        private void НоваяСитуацияToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.NewSituation);
        }

        private void CharacteristicsDataGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            ProcessCharacteristicsGridValueChange(CharacteristicsDataGrid.CurrentCell);             
        }

        private void CharacteristicsDataGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            CharacteristicsDataGrid.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2;
            RenameCharacteristic(e.RowIndex, e.ColumnIndex);            
        }

        private void CharacteristicsDataGrid_CurrentCellChanged(object sender, EventArgs e)
        {            
            UpdateCharacteristicsGridToolBar();
        }

        private void CharacteristicsDataGrid_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {            
            UpdateLastCharacteristicName(e.RowIndex, e.ColumnIndex);            
        }

        private void обычныйToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            ScaleSituationsArea(SituationsHierarchyScale.Normal);
        }

        private void мелкийToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            ScaleSituationsArea(SituationsHierarchyScale.Little);
        }             

        private void панорамаToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ScaleSituationsArea(SituationsHierarchyScale.Panorama);
        }

        private void уменьшитьМасштабToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DoScaleLess();
        }

        private void увеличитьМасштабToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DoScaleLarger();
        }

        private void уменьшенныйToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ScaleSituationsArea(SituationsHierarchyScale.Less);
        }

        private void оченьмелкийToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ScaleSituationsArea(SituationsHierarchyScale.VeryLittle);
        }

        private void удалитьСвязьToolStripMenuItem_Click(object sender, EventArgs e)
        {            
            DeleteSelectedLinkOrSituationBoxesGroup();            
        }

        private void CharacteristicsDataGrid_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            ProcessCharacteristicsGridClick(e.RowIndex,e.ColumnIndex);
        }

        private void УдалитьХарактеристикуToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DeleteCharacteristic();
        }

        private void поднятьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpCharacteristic();
        }

        private void опуститьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DownCharacteristic();
        }

        private void DeleteCharacteristicToolStripButton_Click(object sender, EventArgs e)
        {
            DeleteCharacteristic();
        }

        private void UpCharacteristicToolStripButton_Click(object sender, EventArgs e)
        {
            UpCharacteristic();
        }

        private void DownCharacteristicToolStripButton_Click(object sender, EventArgs e)
        {
            DownCharacteristic();
        }

        private void AddCharacteristicToolStripDropDownButton_DropDownOpening(object sender, EventArgs e)
        {
            UpdateIndicatorsList(AddCharacteristicToolStripDropDownButton.DropDownItems);
        }

        private void RenameCharacteristicToolStripButton_Click(object sender, EventArgs e)
        {
            StartCharacteristicRenaming();
        }

        private void ПереименоватьХарактеристикуToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StartCharacteristicRenaming();
        }

        private void SituationsArea_MouseDown(object sender, MouseEventArgs e)
        {
            if ((CurrentSituationsArea.State == SituationsHierarchyState.Pointer) && (e.Button == MouseButtons.Left))            
            {            
                if (CurrentSituationsArea.MovementWay != Directions2D.None)
                {
                    _mousebuttonPressing = true;
                    ScrollSituationsAreaByMouseDown();
                }
                else
                {
                    CurrentSituationsArea.MultiselectionStartPoint = e.Location;
                    CurrentSituationsArea.MultiselectionEndPoint = e.Location;
                    CurrentSituationsArea.IsMultiselect = true;                    
                }
            }
        }
        

        private void SituationsArea_MouseMove(object sender, MouseEventArgs e)
        {
            CheckMoveState(e.X, e.Y);                 
            if (CurrentSituationsArea.IsMultiselect)
            {
                Point p = e.Location;
                if (CurrentSituationsArea.MultiselectionEndPoint != p)
                {
                    CurrentSituationsArea.MultiselectionEndPoint = p;
                    if (CurrentSituationsArea.MovementWay != Directions2D.None)
                    {
                        ScrollSituationsAreaByMouseDown();
                        RefreshSituationsAreaImmediately();
                    }
                    else
                    {                        
                        RefreshSituationsArea();
                    }
                }
                return;
            }            
            if (CurrentSituationsArea.IsLinkCreatingProcess)
            {
                _curmouseposition = e.Location;
                if (CurrentSituationsArea.MovementWay != Directions2D.None)
                {
                    ScrollSituationsAreaByMouseDown();
                    RefreshSituationsAreaImmediately();
                }
                else
                {
                    RefreshSituationsArea();
                }
            }            
        }

        private void SituationsArea_MouseUp(object sender, MouseEventArgs e)
        {
            CurrentSituationsArea.MultiselectionEndPoint = e.Location;
            FinishMultiselection();
            CurrentSituationsArea.IsMultiselect = false;
            if (_mousebuttonPressing)
            {
                _mousebuttonPressing = false;
                RefreshSituationsArea();
            }
        }

        private void SituationsHierarchyForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey)
            {                
                CurrentSituationsArea.IsMultiselectByCtrl = true;
            }
        }

        private void SituationsHierarchyForm_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey)
            {
                CurrentSituationsArea.IsMultiselectByCtrl = false;
            }
        }
        
        private void splitContainer1_Panel2_Scroll(object sender, ScrollEventArgs e)
        {            
            RefreshMap();            
        }
        
        private void AllLinksToolStripDropDownButton1_DropDownOpening(object sender, EventArgs e)
        {
            PrepareLinksList();
        }

        private void AllLinksToolStripDropDownButton1_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {            
            ProcessLinksListClick(e.ClickedItem);
        }

        private void редактироватьОписаниеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowEditEventDialog();
        }

        private void PhrasesToolStripButton_Click(object sender, EventArgs e)
        {
            ShowEditEventDialog();
        }

        private void редактироватьОписаниеСитуацииToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowEditEventDialog();
        }

        private void переименоватьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StartRenamingOfSelectedSituation();
        }

        private void SituationsAreaContextMenu_Opening(object sender, CancelEventArgs e)
        {
            SituationsHierarchyState bef = CurrentSituationsArea.State;
            SetMode(SituationsHierarchyState.Pointer);
            LinkType lt=ProcessSituationsAreaClick(SituationsAreaPanel.PointToClient(new Point(MousePosition.X, MousePosition.Y)), MouseButtons.Right);
            SetMode(bef);            
            PrepareSituationsAreaContextMenu(lt);
        }

        private void вставитьСитуациюToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SituationsHierarchyState bef = CurrentSituationsArea.State;
            SetMode(SituationsHierarchyState.NewSituation);
            ProcessSituationsAreaClick(SituationsAreaPanel.PointToClient(new Point(SituationsAreaContextMenu.Left, SituationsAreaContextMenu.Top)), MouseButtons.Left);
            SetMode(bef);            
        }

        /// <summary>
        /// Устанавливает новую информацию о направлении МЛВ
        /// </summary>
        private void SetNewBackLIM()
        {
            if (!_programRulesContainerDirty)
            {
                ProjectLink.GetRulesContainerById(_editingRulesContainerId).BackLIM = backLIMcheckbox.Checked;                
            }
        }

        private void изменитьТипСвязиНаСитуацияПодситуацияToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SwitchLinkType();
        }

        private void изменитьТипСвязиНаIsAToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SwitchLinkType();
        }

        private void протянутьСвязьIsAToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.IsA);
        }

        private void протянутьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.Subsituation);
        }

        private void InherKindToolStripButton_Click(object sender, EventArgs e)
        {            
            ShowInheritanceKindDialog(ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId));
        }

        private void изменитьТипНаследованияToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            ShowInheritanceKindDialog(ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId));
        }

        private void изменитьТипНаследованияToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Guid characteristicId = ProjectLink.GetLinkById(CurrentSituationsArea.SelectedLinkLine.RelatedLinkId).SourceCharacteristicId;
            ShowInheritanceKindDialog(ProjectLink.GetCharacteristicById(characteristicId).OwningSituation);
        }

        private void указатьСитуациюСледующийШагToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.NextStep);
        }

        private void указатьСитуациюШагПриНеудачеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.StepOnFail);
        }

        private void связьIsAToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.IsA);
        }

        private void настроитьВероятностьПереходаToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowProbabilityDialog();
        }

        private void ProbabilityToolStripButton_Click(object sender, EventArgs e)
        {
            ShowProbabilityDialog();
        }

        private void связьСитуацияПодситуацияToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.Subsituation);
        }

        private void режимУказаниеСитуацииСледующийШагToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.NextStep);
        }

        private void режимToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetMode(SituationsHierarchyState.StepOnFail);
        }

        private void SituationNameTextbox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == System.Windows.Forms.Keys.Enter)
            {
                RenameSituationThroughCharacteristicsDataGrid();
            }
        }

        private void УдалитьХарактеристикуToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DeleteCharacteristic();
        }
        
        private void ПереименоватьХарактеристикуToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            StartCharacteristicRenaming();
        }

        private void CharacteristicsDataGridContextMenu_Opening(object sender, CancelEventArgs e)
        {            
            SelectCharacteristicByMousePosition(CharacteristicsDataGridContextMenu.Left, CharacteristicsDataGridContextMenu.Top);
            UpdateIndicatorsList(ДобавитьНовуюХарактеристикуToolStripMenuItem.DropDownItems);            
            SituationBox sitbox = CurrentSituationsArea.SelectedSituationBox;
            if (sitbox != null)
            {
                Situation sit = ProjectLink.GetItemById(sitbox.SituationId);
                if (sit != null)
                {
                    DataGridViewRow dr = CharacteristicsDataGrid.SelectedRows[0];
                    string chname = dr.Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
                    Characteristic ch = sit.GetFirstItemByName(chname);
                    ПерейтиКНаивысшемуРодителюХарактеристикиToolStripMenuItem.Visible = ch.ParentCharacteristicId != Guid.Empty;
                    настроитьВероятностьПереходаToolStripMenuItem.Visible = (ch.IndicatorType == IndicatorType.NextStep) || (ch.IndicatorType == IndicatorType.StepOnFail);
                }
            }            
        }

        private void SituationsArea_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey)
            {
                CurrentSituationsArea.IsMultiselectByCtrl = true;
            }
        }

        private void SituationsArea_MouseCaptureChanged(object sender, EventArgs e)
        {
            Directions2D ms = CurrentSituationsArea.MovementWay;
            if (ms != Directions2D.None)
            {
                SplitterPanel sp = splitContainer1.Panel2;
                HScrollProperties hs = sp.HorizontalScroll;
                VScrollProperties vs = sp.VerticalScroll;
                int newx = hs.Value;
                int newy = vs.Value;
                switch (ms)
                {
                    case Directions2D.Left:
                        newx = hs.Value - SituationsArea.MouseSituationDistance;
                        if (newx < 0)
                        {
                            newx = 0;
                        }
                        break;
                    case Directions2D.Right:
                        newx = hs.Value + SituationsArea.MouseSituationDistance;
                        if (newx > hs.Maximum)
                        {
                            newx = hs.Maximum;
                        }
                        break;
                    case Directions2D.Up:
                        newy = vs.Value - SituationsArea.MouseSituationDistance;
                        if (newy < 0)
                        {
                            newy = 0;
                        }
                        break;
                    case Directions2D.Down:
                        newy = vs.Value + SituationsArea.MouseSituationDistance;
                        if (newy > vs.Maximum)
                        {
                            newy = vs.Maximum;
                        }
                        break;
                }
                sp.AutoScrollPosition = new Point(newx, newy);
            }
        }

        /// <summary>
        /// Обновляет доступность кнопок работы с правилами контейнера правил
        /// </summary>
        private void UpdateRulesAbilities()
        {
            bool ruleselected = _selectedRuleIndex != -1;
            EditRuleButton.Enabled = ruleselected;
            DeleteRuleButton.Enabled = ruleselected;
            DoubleRuleButton.Enabled = ruleselected;
            UpRuleButton.Enabled = ruleselected && (_selectedRuleIndex >= 1);
            DownRuleButton.Enabled = ruleselected && (_selectedRuleIndex < (_rulesBorders.Count - 1));
        }

        /// <summary>
        /// Обновляет выделение в правилах
        /// </summary>
        private void UpdateRulesSelection()
        {
            ListBox.SelectedIndexCollection sels = RulesListBox.SelectedIndices;
            sels.Clear();
            if (_selectedRuleIndex != -1)
            {
                Point border = _rulesBorders[_selectedRuleIndex];
                for (int k = border.X; k <= border.Y; k++)
                {
                    sels.Add(k);
                }
            }
            UpdateRulesAbilities();
        }

        /// <summary>
        /// Отображает диалог редактирования типа наследования по связи Is A
        /// </summary>
        private static void ShowInheritanceKindDialog(Situation situation)
        {
            InheritanceKindDialog inhd = new InheritanceKindDialog(situation);
            inhd.ShowDialog();
        }

        /// <summary>
        /// Отображает диалог настройки вероятности перехода (для характеристик "следующий шаг" и "шаг при неудаче")
        /// </summary>        
        private void ShowProbabilityDialog()
        {
            SituationBox sitbox = CurrentSituationsArea.SelectedSituationBox;
            if (sitbox != null)
            {
                Situation sit = ProjectLink.GetItemById(sitbox.SituationId);
                if (sit != null)
                {
                    DataGridViewRow dr = CharacteristicsDataGrid.SelectedRows[0];
                    string chname = dr.Cells[GetIndexOfColumn(CharacteristicsDataGridColumn.Name)].Value as string;
                    Characteristic ch = sit.GetFirstItemByName(chname);
                    if (ch != null)
                    {
                        ProbabilityDialog prob = new ProbabilityDialog(ch);
                        prob.ShowDialog();
                    }
                }
            }
        }

        /// <summary>
        /// Выбирает правило контейнера правил по нажатию клавиши
        /// </summary>
        /// <param name="key"></param>
        private void SelectRuleByKeyPress(Keys key)
        {
            switch (key)
            {
                case Keys.Up:
                    if (_selectedRuleIndex>=1)
                    {
                        _selectedRuleIndex--;
                        UpdateRulesSelection();
                    }
                    break;
                case Keys.Down:
                    if ((_selectedRuleIndex != -1) && (_selectedRuleIndex < (_rulesBorders.Count - 1)))                    
                    {
                        _selectedRuleIndex++;
                        UpdateRulesSelection();
                    }
                    break;
                case Keys.Enter:
                    if (_selectedRuleIndex != -1)
                    {
                        EditRule();                    
                    }
                    break;
            }
        }

        /// <summary>
        /// Выбирает правило контейнера правил по X и Y координатам мышки
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void SelectRule(int x, int y)
        {
            ListBox.ObjectCollection items = RulesListBox.Items;            
            int c = items.Count;
            for (int i = 0; i < c; i++)            
            {
                Rectangle rect = RulesListBox.GetItemRectangle(i);
                if (rect.Contains(x, y))
                {                    
                    int cc = _rulesBorders.Count;
                    for (int j = 0; j < cc; j++)                    
                    {
                        Point border = _rulesBorders[j];
                        if ((i >= border.X) && (i <= border.Y))
                        {                            
                            _selectedRuleIndex = j;
                            break;
                        }                        
                    }
                    break;
                }                
            }
            UpdateRulesSelection();            
        }

        /// <summary>
        /// Обновляет список правил в контейнере правил
        /// </summary>
        /// <param name="rulesContainer"></param>
        private void RefreshRulesList(RulesContainer rulesContainer)
        {
            ListBox.ObjectCollection items = RulesListBox.Items;
            items.Clear();
            _rulesBorders = new List<Point>();
            if (rulesContainer != null)
            {
                int c = rulesContainer.ItemsCount;
                for (int i = 0; i < c; i++)
                {
                    SoftwareConsulting.BI11.Studio.Core.Project.SituationsHierarchy.RulesContainers.Rule rule = rulesContainer.GetItemByPosition(i);
                    Point border = new Point();
                    border.X = items.Count;
                    items.AddRange(rule.ToString().ToArray());
                    border.Y = items.Count - 1;
                    _rulesBorders.Add(border);
                    items.Add("");
                }                                
            }            
            UpdateRulesSelection();
        }

        /// <summary>
        /// Обновляет комбик с целью вывода контейнера правил
        /// </summary>
        private void RefreshRulesContainerAim(RulesContainer rulesContainer)
        {
            ComboBox.ObjectCollection citems = RulesContainerAimCombo.Items;
            citems.Clear();
            citems.AddRange(ProjectLink.GetAllCharacteristicsForRulesContainerEditor(IndicatorType.None, Guid.Empty).ToArray());
            PathToValue aim = rulesContainer.AimVariable;
            if (aim != null)
            {
                if (aim.Kind == PathToValueKind.DateAndFactCorrelationsCharacteristic)
                {
                    citems.Add(aim.ToStringUsingWithSituation(Guid.Empty));
                }
                //выбираем в комбике текущую цель
                RulesContainerAimCombo.SelectedItem = aim.ToStringUsingWithSituation(Guid.Empty);
            }
        }

        /// <summary>
        /// Обновление информации о контейнере правил
        /// </summary>
        private void RefreshRulesContainer(RulesContainer rc)
        {
            RefreshRulesList(rc);
            _programRulesContainerDirty = true;
            backLIMcheckbox.Checked = rc.BackLIM;
            RefreshRulesContainerAim(rc);
            _programRulesContainerDirty = false;
        }

        /// <summary>
        /// Применяет выбранное значение комбика в качестве цели контейнера правил
        /// </summary>
        private void ApplyNewRulesContainerAim()
        {
            if (!_programRulesContainerDirty)
            {
                RulesContainer prod = ProjectLink.GetRulesContainerById(_editingRulesContainerId);
                if (prod.AimVariable == null)
                {
                    Characteristic ch = ProjectLink.GetCharacteristicById(_editingCharacteristicWithRulesContainerId);
                    Situation sit = ch.OwningSituation;
                    Characteristic ch2 = sit.GetFirstCharacteristicByIndicatorType(IndicatorType.Result);
                    string chname = ch2 == null ? "" : ch2.Name;                    
                    prod.AimVariable = new PathToValue(PathToValueKind.NormalCharacteristic, chname, ProjectLink);
                }
                FixedDimensionItemsPointer cip = prod.AimVariable.ParseElementAndApply(RulesContainerAimCombo.Text, Guid.Empty, null);
                if (cip != null)
                {
                    cip = ShowFixedDimensionItemsDialog(cip);
                    if (Assert.FailIfNot(prod.AimVariable.ParseElementAndApply("", Guid.Empty, cip) == null, Assert.Id.Assert00165))
                    {                    
                        RefreshRulesContainerAim(prod);//чтобы выбранная ячейка куба подставилась в комбик
                    }
                }
            }
        }

        /// <summary>
        /// Поднимает выделенное правило
        /// </summary>
        private void UpRule()
        {
            RulesContainer rcon = ProjectLink.GetRulesContainerById(_editingRulesContainerId);
            var r1 = rcon.GetItemByPosition(_selectedRuleIndex);
            var r2 = rcon.GetItemByPosition(_selectedRuleIndex - 1);
            rcon.SwapItems(r1, r2);
            _selectedRuleIndex--;
            RefreshRulesList(rcon);
        }

        /// <summary>
        /// Опускает выделенное правило
        /// </summary>
        private void DownRule()
        {
            RulesContainer rcon = ProjectLink.GetRulesContainerById(_editingRulesContainerId);
            var r1 = rcon.GetItemByPosition(_selectedRuleIndex);
            var r2 = rcon.GetItemByPosition(_selectedRuleIndex + 1);
            rcon.SwapItems(r1, r2);
            _selectedRuleIndex++;
            RefreshRulesList(rcon);
        }

        /// <summary>
        /// Отображает диалог редактирования правила контейнера правил
        /// </summary>
        private void EditRule()
        {
            RulesContainer rc = ProjectLink.GetRulesContainerById(_editingRulesContainerId);
            if (_selectedRuleIndex != -1)
            {
                SoftwareConsulting.BI11.Studio.Core.Project.SituationsHierarchy.RulesContainers.Rule rule = rc.GetItemByPosition(_selectedRuleIndex);
                Guid sitid = ProjectLink.GetCharacteristicById(_editingCharacteristicWithRulesContainerId).OwningSituation.Id;
                EditRuleDialog rdi = new EditRuleDialog(sitid, rule, CurrentSituationsArea.ProjectExplorerLink);
                rdi.ShowDialog();
                RefreshRulesList(rc);
            }
        }

        /// <summary>
        /// Удаляет выбранное правило контейнера правил
        /// </summary>
        private void DeleteRule()
        {
            RulesContainer rc = ProjectLink.GetRulesContainerById(_editingRulesContainerId);
            rc.DeleteByPosition(_selectedRuleIndex);
            int c = rc.ItemsCount;
            if ((c == 0) || (_selectedRuleIndex >= c))
            {
                _selectedRuleIndex = -1;
            }
            RefreshRulesList(rc);
        }

        /// <summary>
        /// Дублирует выбранное правило контейнера правил
        /// </summary>
        private void CreateRuleClone()
        {
            RulesContainer rc = ProjectLink.GetRulesContainerById(_editingRulesContainerId);
            SoftwareConsulting.BI11.Studio.Core.Project.SituationsHierarchy.RulesContainers.Rule r = rc.GetItemByPosition(_selectedRuleIndex);
            int toswap = -1;
            if (_selectedRuleIndex < (rc.ItemsCount - 1))
            {
                toswap = _selectedRuleIndex + 1;
            }           
            var dr = r.CreateClone();
            rc.Add(dr);
            if (toswap != -1)
            {
                rc.SwapItems(rc.GetItemByPosition(toswap), dr);
            }
            _selectedRuleIndex++;
            RefreshRulesList(rc);
        }
        
        /// <summary>
        /// Отображает диалог добавления нового правила
        /// </summary>
        private void AddNewRule()
        {
            RulesContainer rc = ProjectLink.GetRulesContainerById(_editingRulesContainerId);
            Reason reason = new Reason(ProjectLink);
            Conclusion conclusion = new Conclusion(ProjectLink);
            var _rule = new SoftwareConsulting.BI11.Studio.Core.Project.SituationsHierarchy.RulesContainers.Rule(reason, conclusion, rc);
            rc.Add(_rule);
            RefreshRulesList(rc);            
        }

        private void MapPanel_Paint(object sender, PaintEventArgs e)
        {
            UpdateMapPanel(e.Graphics);
        }

        private void MapPanel_MouseDown(object sender, MouseEventArgs e)
        {
            _mapscrolling = true;
            ExecuteMapScrolling(e);
        }

        private void MapPanel_MouseUp(object sender, MouseEventArgs e)
        {
            _mapscrolling = false;
        }

        private void MapPanel_MouseLeave(object sender, EventArgs e)
        {
            _mapscrolling = false;
        }

        private void MapPanel_MouseMove(object sender, MouseEventArgs e)
        {
            ExecuteMapScrolling(e);
        }

        private void CenterSituationToolStripButton_Click(object sender, EventArgs e)
        {
            CenterSelectedSituation();
        }

        private void GoToFirstParentToolStripButton_Click(object sender, EventArgs e)
        {
            GoToCharacteristicFirstParent();
        }

        private void перейтиКВысшемуРодителюToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GoToCharacteristicFirstParent();
        }

        private void ПерейтиКНаивысшемуРодителюХарактеристикиToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GoToCharacteristicFirstParent();
        }

        private void СитуациюToolStripMenuItem_Click(object sender, EventArgs e)
        {
            IncludeOrExcludeSelectedSituation(false, false);
        }

        private void СитуациюToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            IncludeOrExcludeSelectedSituation(true, false);
        }

        private void всюВетвьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            IncludeOrExcludeSelectedSituation(false, true);
        }

        private void всюВетвьToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            IncludeOrExcludeSelectedSituation(true, true);
        }

        private void породитьДочернююСитуациюToolStripMenuItem_Click(object sender, EventArgs e)
        {
            BurnChildSituation();
        }

        private void найтиСитуациюToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowFindSituationDialog();
        }

        private void SearchToolStripButton_Click(object sender, EventArgs e)
        {
            ShowFindSituationDialog();
        }

        private void RulesContainerOKButton_Click(object sender, EventArgs e)
        {
            ShowOrHideRulesContainerEditor(ProjectLink.GetCharacteristicById(_editingCharacteristicWithRulesContainerId), false);
        }

        private void backLIMcheckbox_CheckedChanged(object sender, EventArgs e)
        {
            SetNewBackLIM();
        }

        private void AddRuleButton_Click(object sender, EventArgs e)
        {
            AddNewRule();
        }

        private void backLIMcheckbox_CheckedChanged_1(object sender, EventArgs e)
        {
            SetNewBackLIM();
        }

        private void RulesContainerOKButton_Click_1(object sender, EventArgs e)
        {
            ShowOrHideRulesContainerEditor(ProjectLink.GetCharacteristicById(_editingCharacteristicWithRulesContainerId), false);
            _editingRulesContainerId = Guid.Empty;
        }

        private void AddRuleButton_Click_1(object sender, EventArgs e)
        {
            AddNewRule();
        }

        private void RulesContainerAimCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            ApplyNewRulesContainerAim();
        }

        private void EditRuleButton_Click(object sender, EventArgs e)
        {
            EditRule();
        }

        private void DeleteRuleButton_Click(object sender, EventArgs e)
        {
            DeleteRule();
        }

        private void UpRuleButton_Click(object sender, EventArgs e)
        {
            UpRule();
        }

        private void DownRuleButton_Click(object sender, EventArgs e)
        {
            DownRule();
        }

        private void RulesListBox_KeyDown(object sender, KeyEventArgs e)
        {
            SelectRuleByKeyPress(e.KeyCode);
        }

        private void RulesListBox_MouseDown(object sender, MouseEventArgs e)
        {
            SelectRule(e.X, e.Y);
        }

        private void DoubleRuleButton_Click(object sender, EventArgs e)
        {
            CreateRuleClone();
        }

        private void RulesListBox_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            EditRule();
        }

        private void SituationBoxContextMenu_Opening(object sender, CancelEventArgs e)
        {
            изменитьТипНаследованияToolStripMenuItem1.Enabled = ProjectLink.GetItemById(CurrentSituationsArea.SelectedSituationBox.SituationId).IsA != null;
        }     
    }
}
